diff --git a/.docker/dist.tar.gz b/.docker/dist.tar.gz deleted file mode 100644 index 411c92f64cd600841b98f1375c32b920895df2e0..0000000000000000000000000000000000000000 Binary files a/.docker/dist.tar.gz and /dev/null differ diff --git a/.docker/docker-compose.yml b/.docker/docker-compose.yml index 54b7b8edbbe0652379fc74c5a81a58ada8a57e3a..1b826fedfdaa47fe087d255dff50723d1dc9e25d 100644 --- a/.docker/docker-compose.yml +++ b/.docker/docker-compose.yml @@ -7,13 +7,15 @@ volumes: search-db-data: storage-service-data: identity-service-data: + metric-db-data: + dashboard-service-data: services: dbrepo-metadata-db: restart: "no" container_name: dbrepo-metadata-db hostname: metadata-db - image: docker.io/bitnami/mariadb:11.1.3-debian-11-r6 + image: docker.io/bitnami/mariadb-galera:11.1.3-debian-11-r8 volumes: - metadata-db-data:/bitnami/mariadb - ./config/1_setup-schema.sql:/docker-entrypoint-initdb.d/1_setup-schema.sql @@ -23,6 +25,7 @@ services: environment: MARIADB_DATABASE: "${METADATA_DB:-dbrepo}" MARIADB_ROOT_PASSWORD: "${METADATA_DB_PASSWORD:-dbrepo}" + MARIADB_GALERA_MARIABACKUP_PASSWORD: "${METADATA_DB_BACKUP_PASSWORD:-dbrepobackup}" healthcheck: test: mysqladmin ping --user=root --password="${METADATA_DB_PASSWORD:-dbrepo}" --silent interval: 10s @@ -35,7 +38,7 @@ services: restart: "no" container_name: dbrepo-data-db hostname: data-db - image: docker.io/bitnami/mariadb:11.1.3-debian-11-r6 + image: docker.io/bitnami/mariadb-galera:11.1.3-debian-11-r8 volumes: - data-db-data:/bitnami/mariadb - "${SHARED_VOLUME:-/tmp}:/tmp" @@ -43,6 +46,7 @@ services: - "3307:3306" environment: MARIADB_ROOT_PASSWORD: "${DATA_DB_PASSWORD:-dbrepo}" + MARIADB_GALERA_MARIABACKUP_PASSWORD: "${DATA_DB_BACKUP_PASSWORD:-dbrepobackup}" healthcheck: test: mysqladmin ping --user=root --password="${DATA_DB_PASSWORD:-dbrepo}" --silent interval: 10s @@ -55,16 +59,16 @@ services: restart: "no" container_name: dbrepo-auth-db hostname: auth-db - image: docker.io/bitnami/mariadb:11.1.3-debian-11-r6 + image: docker.io/bitnami/postgresql:17.0.0-debian-12-r1 volumes: - - auth-db-data:/bitnami/mariadb - ports: - - "3308:3306" + - auth-db-data:/bitnami/postgresql environment: - MARIADB_DATABASE: "${AUTH_DB_NAME:-keycloak}" - MARIADB_ROOT_PASSWORD: "${AUTH_DB_PASSWORD:-dbrepo}" + POSTGRESQL_DATABASE: "${AUTH_DB_NAME:-keycloak}" + POSTGRESQL_USERNAME: "${AUTH_DB_USERNAME:-keycloak}" + POSTGRESQL_PASSWORD: "${AUTH_DB_PASSWORD:-dbrepo}" + PGPASSWORD: "${AUTH_DB_PASSWORD:-dbrepo}" healthcheck: - test: mysqladmin ping --user=root --password="${AUTH_DB_PASSWORD:-dbrepo}" --silent + test: "psql -U ${AUTH_DB_USERNAME:-keycloak} -h 127.0.0.1 -p 5432 -d ${AUTH_DB_NAME:-keycloak} -c 'select version();'" interval: 15s timeout: 5s retries: 12 @@ -75,18 +79,24 @@ services: restart: "no" container_name: dbrepo-auth-service hostname: auth-service - image: registry.datalab.tuwien.ac.at/dbrepo/auth-service:1.4.5 + image: bitnami/keycloak:26.0.0-debian-12-r1 + volumes: + - ./config/import-realms.sh:/docker-entrypoint-initdb.d/import-realms.sh + - ./config/master-realm.json:/opt/keycloak/data/import/master-realm.json + - ./config/dbrepo-realm.json:/opt/keycloak/data/import/dbrepo-realm.json + environment: + KEYCLOAK_ENABLE_HTTPS: "false" + KEYCLOAK_ENABLE_STATISTICS: "true" + KEYCLOAK_ENABLE_HEALTH_ENDPOINTS: "true" + KEYCLOAK_DATABASE_HOST: "auth-db" + KEYCLOAK_DATABASE_NAME: "${AUTH_DB_NAME:-keycloak}" + KEYCLOAK_DATABASE_USER: "${AUTH_DB_USERNAME:-keycloak}" + KEYCLOAK_DATABASE_PASSWORD: "${AUTH_DB_PASSWORD:-dbrepo}" healthcheck: - test: curl -sSL 'http://0.0.0.0:8080/realms/dbrepo' | grep "dbrepo" || exit 1 - interval: 15s + test: curl --head -fsS http://localhost:9000/health/ready + interval: 10s timeout: 5s retries: 12 - environment: - AUTH_DB: "${AUTH_DB:-keycloak}" - KC_DB_USERNAME: root - KC_DB_PASSWORD: "${AUTH_DB_PASSWORD:-dbrepo}" - KEYCLOAK_ADMIN: "${AUTH_SERVICE_ADMIN_USERNAME:-admin}" - KEYCLOAK_ADMIN_PASSWORD: "${AUTH_SERVICE_ADMIN_PASSWORD:-admin}" depends_on: dbrepo-identity-service: condition: service_healthy @@ -99,7 +109,7 @@ services: restart: "no" container_name: dbrepo-metadata-service hostname: metadata-service - image: registry.datalab.tuwien.ac.at/dbrepo/metadata-service:1.4.5 + image: registry.datalab.tuwien.ac.at/dbrepo/metadata-service:1.4.7 volumes: - "${SHARED_VOLUME:-/tmp}:/tmp" environment: @@ -162,7 +172,7 @@ services: restart: "no" container_name: dbrepo-analyse-service hostname: analyse-service - image: registry.datalab.tuwien.ac.at/dbrepo/analyse-service:1.4.5 + image: registry.datalab.tuwien.ac.at/dbrepo/analyse-service:1.4.7 environment: AUTH_SERVICE_CLIENT: ${AUTH_SERVICE_CLIENT:-dbrepo-client} AUTH_SERVICE_CLIENT_SECRET: ${AUTH_SERVICE_CLIENT:-MUwRc7yfXSJwX8AdRMWaQC3Nep1VjwgG} @@ -188,15 +198,18 @@ services: restart: "no" container_name: dbrepo-broker-service hostname: broker-service - image: docker.io/bitnami/rabbitmq:3.12-debian-12 + image: docker.io/bitnami/rabbitmq:3.13.7-debian-12-r4 ports: - 5672:5672 + - 1883:1883 volumes: - ./config/rabbitmq.conf:/etc/rabbitmq/rabbitmq.conf - ./config/advanced.config:/etc/rabbitmq/advanced.config - ./config/enabled_plugins:/etc/rabbitmq/enabled_plugins - ./config/definitions.json:/app/definitions.json - broker-service-data:/bitnami/rabbitmq/mnesia + environment: + RABBITMQ_FEATURE_FLAGS: mqtt_v5 depends_on: dbrepo-identity-service: condition: service_healthy @@ -212,7 +225,7 @@ services: restart: "no" container_name: dbrepo-search-db hostname: search-db - image: registry.datalab.tuwien.ac.at/dbrepo/search-db:1.4.5 + image: registry.datalab.tuwien.ac.at/dbrepo/search-db:1.4.7 healthcheck: test: curl -sSL localhost:9200/_plugins/_security/health | jq .status | grep UP interval: 10s @@ -236,7 +249,7 @@ services: restart: "no" container_name: dbrepo-search-service hostname: search-service - image: registry.datalab.tuwien.ac.at/dbrepo/search-service:1.4.5 + image: registry.datalab.tuwien.ac.at/dbrepo/search-service:1.4.7 environment: AUTH_SERVICE_CLIENT: ${AUTH_SERVICE_CLIENT:-dbrepo-client} AUTH_SERVICE_CLIENT_SECRET: ${AUTH_SERVICE_CLIENT_SECRET:-MUwRc7yfXSJwX8AdRMWaQC3Nep1VjwgG} @@ -248,12 +261,17 @@ services: OPENSEARCH_USERNAME: ${SEARCH_DB_USERNAME:-admin} OPENSEARCH_PASSWORD: ${SEARCH_DB_PASSWORD:-admin} LOG_LEVEL: ${LOG_LEVEL:-info} + healthcheck: + test: curl -sSL localhost:8080/health | grep 'UP' || exit 1 + interval: 10s + timeout: 5s + retries: 12 dbrepo-data-db-sidecar: restart: "no" container_name: dbrepo-data-db-sidecar hostname: data-db-sidecar - image: registry.datalab.tuwien.ac.at/dbrepo/data-db-sidecar:1.4.5 + image: registry.datalab.tuwien.ac.at/dbrepo/data-db-sidecar:1.4.7 environment: S3_ACCESS_KEY_ID: "${S3_ACCESS_KEY_ID:-seaweedfsadmin}" S3_BUCKET: "${S3_BUCKET:-dbrepo}" @@ -274,18 +292,18 @@ services: restart: "no" container_name: dbrepo-ui hostname: ui - image: registry.datalab.tuwien.ac.at/dbrepo/ui:1.4.5 + image: registry.datalab.tuwien.ac.at/dbrepo/ui:1.4.7 environment: NUXT_PUBLIC_API_CLIENT: "${BASE_URL:-http://localhost}" NUXT_PUBLIC_API_SERVER: "${BASE_URL:-http://localhost}" NUXT_PUBLIC_UPLOAD_CLIENT: "${BASE_URL:-http://localhost}/api/upload/files" depends_on: dbrepo-search-service: - condition: service_started - dbrepo-storage-service: + condition: service_healthy + dbrepo-upload-service: condition: service_healthy healthcheck: - test: wget -qO- localhost:3000 | grep "Database Repository" || exit 1 + test: curl -fsSL http://127.0.0.1:3000 && curl -fsSL http://127.0.0.1:3000/health interval: 10s timeout: 5s retries: 12 @@ -305,8 +323,6 @@ services: depends_on: dbrepo-analyse-service: condition: service_healthy - dbrepo-auth-service: - condition: service_healthy dbrepo-broker-service: condition: service_healthy dbrepo-metadata-service: @@ -341,9 +357,10 @@ services: dbrepo-search-service-init: restart: "no" + init: true container_name: dbrepo-search-service-init hostname: search-service-init - image: registry.datalab.tuwien.ac.at/dbrepo/search-service-init:1.4.5 + image: registry.datalab.tuwien.ac.at/dbrepo/search-service-init:1.4.7 environment: METADATA_SERVICE_ENDPOINT: ${METADATA_SERVICE_ENDPOINT:-http://metadata-service:8080} OPENSEARCH_HOST: ${OPENSEARCH_HOST:-search-db} @@ -353,6 +370,8 @@ services: depends_on: dbrepo-search-db: condition: service_healthy + dbrepo-metadata-service: + condition: service_healthy logging: driver: json-file @@ -361,7 +380,7 @@ services: container_name: dbrepo-storage-service hostname: storage-service image: docker.io/chrislusf/seaweedfs:3.59 - command: [ "server", "-dir=/data", "-s3", "-s3.port=9000", "-s3.config=/app/s3_config.json", "-metricsPort=9091" ] + command: [ "server", "-dir=/data", "-s3", "-s3.port=9000", "-s3.config=/app/s3_config.json", "-metricsPort=9090" ] volumes: - ./config/s3_config.json:/app/s3_config.json - storage-service-data:/data @@ -375,11 +394,48 @@ services: logging: driver: json-file + dbrepo-metric-db: + restart: "no" + container_name: dbrepo-metric-db + hostname: metric-db + image: bitnami/prometheus:2.54.1-debian-12-r4 + volumes: + - ./config/prometheus.yml:/etc/prometheus/prometheus.yml + - metric-db-data:/opt/bitnami/prometheus/data + healthcheck: + test: promtool check healthy + interval: 10s + timeout: 5s + retries: 12 + logging: + driver: json-file + + dbrepo-dashboard-service: + restart: "no" + container_name: dbrepo-dashboard-service + hostname: dashboard-service + image: registry.datalab.tuwien.ac.at/dbrepo/dashboard-service:1.4.7 + environment: + LDAP_ADMIN_USERNAME: "${IDENTITY_SERVICE_ADMIN_USERNAME:-admin}" + LDAP_ADMIN_PASSWORD: "${IDENTITY_SERVICE_ADMIN_PASSWORD:-admin}" + LDAP_ROOT: "${IDENTITY_SERVICE_ROOT:-dc=dbrepo,dc=at}" + healthcheck: + test: test -f /opt/bitnami/grafana/tmp/grafana.pid + interval: 10s + timeout: 5s + retries: 12 + depends_on: + dbrepo-metric-db: + condition: service_started + logging: + driver: json-file + dbrepo-storage-service-init: restart: "no" + init: true container_name: dbrepo-storage-service-init hostname: storage-service-init - image: registry.datalab.tuwien.ac.at/dbrepo/storage-service-init:1.4.5 + image: registry.datalab.tuwien.ac.at/dbrepo/storage-service-init:1.4.7 environment: WEED_CLUSTER_SW_MASTER: "${STORAGE_SERVICE_MASTER_ENDPOINT:-storage-service:9333}" S3_BUCKET: "${S3_BUCKET:-dbrepo}" @@ -419,7 +475,7 @@ services: restart: "no" container_name: dbrepo-data-service hostname: data-service - image: registry.datalab.tuwien.ac.at/dbrepo/data-service:1.4.5 + image: registry.datalab.tuwien.ac.at/dbrepo/data-service:1.4.7 volumes: - "${SHARED_VOLUME:-/tmp}:/tmp" environment: @@ -433,7 +489,7 @@ services: BROKER_HOST: "${BROKER_ENDPOINT:-broker-service}" BROKER_PASSWORD: "${SYSTEM_PASSWORD:-admin}" BROKER_PORT: ${BROKER_PORT:-5672} - BROKER_SERVICE_ENDPOINT: "${BROKER_SERVICE_ENDPOINT:-http://gateway-service/admin/broker}" + BROKER_SERVICE_ENDPOINT: "${BROKER_SERVICE_ENDPOINT:-http://broker-service:15672}" BROKER_USERNAME: "${SYSTEM_USERNAME:-admin}" BROKER_VIRTUALHOST: "${BROKER_VIRTUALHOST:-dbrepo}" CONNECTION_TIMEOUT: ${CONNECTION_TIMEOUT:-60000} diff --git a/.docs/.swagger/api.base.yaml b/.docs/.swagger/api.base.yaml index c7b01fab0ebd3aebaa2f61dd68afdec362ccf236..b7bd0570eea5eeee9cb656bd55d88b25edd361a9 100644 --- a/.docs/.swagger/api.base.yaml +++ b/.docs/.swagger/api.base.yaml @@ -11,7 +11,7 @@ components: type: http externalDocs: description: Project Website - url: https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/ + url: https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.4.7/ info: contact: email: andreas.rauber@tuwien.ac.at @@ -24,7 +24,7 @@ info: name: Apache 2.0 url: https://www.apache.org/licenses/LICENSE-2.0 title: DBRepo REST API - version: 1.4.4 + version: 1.4.7 openapi: 3.1.0 servers: - description: Test Instance diff --git a/.docs/.swagger/api.yaml b/.docs/.swagger/api.yaml index c5c2b5ee8dccd425d7fb5bf570c7f3379b52e210..a3f7eea7f2d4a34a3108ed41e5be9c0500615565 100644 --- a/.docs/.swagger/api.yaml +++ b/.docs/.swagger/api.yaml @@ -16,7 +16,7 @@ info: name: Apache 2.0 url: 'https://www.apache.org/licenses/LICENSE-2.0' title: DBRepo REST API - version: 1.4.4 + version: 1.4.7 servers: - description: Test Instance url: 'https://test.dbrepo.tuwien.ac.at' @@ -929,7 +929,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/ImportCsvDto' + $ref: '#/components/schemas/ImportDto' required: true responses: '202': @@ -1021,7 +1021,7 @@ paths: summary: Create subset description: >- Creates a subset in the query store of the data database. Requires role - `execute-query` + `execute-query` for private databases. operationId: create parameters: - name: databaseId @@ -1223,7 +1223,7 @@ paths: Gets data from table with id as downloadable file. For tables in private databases, the user needs to have at least *READ* access to the associated database. - operationId: exportData + operationId: exportDataset parameters: - name: databaseId in: path @@ -1431,6 +1431,12 @@ paths: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' + '423': + description: Database quota exceeded + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' '502': description: Connection to search service failed content: @@ -3030,6 +3036,12 @@ paths: summary: List users description: Lists users known to the metadata database. operationId: findAll + parameters: + - name: username + in: query + required: false + schema: + type: string responses: '200': description: List users @@ -5593,7 +5605,7 @@ components: type: object additionalProperties: type: object - ImportCsvDto: + ImportDto: required: - location - separator @@ -5612,13 +5624,6 @@ components: minimum: 0 type: integer format: int64 - false_element: - type: string - true_element: - type: string - null_element: - type: string - example: NA line_termination: type: string example: \r\n @@ -5748,6 +5753,7 @@ components: - longblob - enum - set + - serial - bit - tinyint - bool @@ -5765,7 +5771,6 @@ components: - year ColumnDto: required: - - auto_generated - column_type - database_id - id @@ -5833,11 +5838,6 @@ components: minLength: 0 type: string example: mdb_date - date_format: - $ref: '#/components/schemas/ImageDateDto' - auto_generated: - type: boolean - example: false index_length: type: integer format: int64 @@ -5862,6 +5862,7 @@ components: - longblob - enum - set + - serial - bit - tinyint - bool @@ -5952,12 +5953,14 @@ components: $ref: '#/components/schemas/PrimaryKeyDto' ContainerDto: required: + - count - created - host - id - image - internal_name - name + - quota - sidecar_host - sidecar_port type: object @@ -5975,6 +5978,14 @@ components: format: int32 image: $ref: '#/components/schemas/ImageDto' + quota: + type: integer + format: int64 + example: 50 + count: + type: integer + format: int64 + example: 10 created: type: string format: date-time @@ -5992,6 +6003,64 @@ components: ui_port: type: integer format: int32 + DataTypeDto: + required: + - display_name + - documentation + - is_buildable + - is_quoted + - value + type: object + properties: + value: + type: string + example: time + documentation: + type: string + example: 'https://mariadb.com/kb/en/time/' + display_name: + type: string + example: TIME(fsp) + size_min: + type: integer + format: int32 + example: 0 + size_max: + type: integer + format: int32 + example: 6 + size_default: + type: integer + format: int32 + example: 0 + size_required: + type: boolean + example: false + d_min: + type: integer + format: int32 + d_max: + type: integer + format: int32 + d_default: + type: integer + format: int32 + d_required: + type: boolean + data_hint: + type: string + example: 'e.g. HH:MM:SS, HH:MM, HHMMSS, H:M:S' + type_hint: + type: string + example: 'fsp=microsecond precision, min. 0, max. 6' + is_quoted: + type: boolean + description: frontend needs to quote this data type + example: false + is_buildable: + type: boolean + description: frontend can build this data type + example: true DatabaseAccessDto: required: - created @@ -6142,33 +6211,10 @@ components: $ref: '#/components/schemas/ForeignKeyBriefDto' referenced_column: $ref: '#/components/schemas/ColumnBriefDto' - ImageDateDto: - required: - - created_at - - database_format - - has_time - - id - - unix_format - type: object - properties: - id: - type: integer - format: int64 - database_format: - type: string - example: '%d.%c.%Y' - unix_format: - type: string - example: dd.MM.YYYY - has_time: - type: boolean - example: false - created_at: - type: string - format: date-time - example: '2021-03-12T15:26:21.000Z' ImageDto: required: + - data_types + - default - default_port - dialect - driver_class @@ -6197,17 +6243,20 @@ components: driver_class: type: string example: org.mariadb.jdbc.Driver - date_formats: - type: array - items: - $ref: '#/components/schemas/ImageDateDto' jdbc_method: type: string example: mariadb + default: + type: boolean + example: false default_port: type: integer format: int32 example: 3306 + data_types: + type: array + items: + $ref: '#/components/schemas/DataTypeDto' PrimaryKeyDto: required: - column @@ -6468,8 +6517,6 @@ components: minLength: 0 type: string example: mdb_date - date_format: - $ref: '#/components/schemas/ImageDateDto' auto_generated: type: boolean example: false @@ -6497,6 +6544,7 @@ components: - longblob - enum - set + - serial - bit - tinyint - bool @@ -7742,6 +7790,7 @@ components: - default_port - dialect - driver_class + - is_default - jdbc_method - name - registry @@ -7758,6 +7807,9 @@ components: type: string dialect: type: string + is_default: + type: boolean + example: false driver_class: type: string jdbc_method: @@ -8139,6 +8191,7 @@ components: - longblob - enum - set + - serial - bit - tinyint - bool @@ -8167,10 +8220,6 @@ components: minLength: 0 type: string example: Formatted as YYYY-MM-dd - dfid: - type: integer - description: date format id - format: int64 enums: type: array description: 'enum values, only considered when type = ENUM' @@ -8284,6 +8333,7 @@ components: - name - privileged_password - privileged_username + - quota - sidecar_host - sidecar_port type: object @@ -8298,6 +8348,10 @@ components: type: integer description: Port of container format: int32 + quota: + type: integer + format: int64 + example: 50 image_id: type: integer description: Image ID @@ -8374,14 +8428,14 @@ components: type: string resumptionToken: type: string - untilDate: + parametersString: type: string - format: date-time fromDate: type: string format: date-time - parametersString: + untilDate: type: string + format: date-time BannerMessageDto: required: - id @@ -8417,6 +8471,7 @@ components: example: '2021-03-12T15:26:21.000Z' ImageBriefDto: required: + - default - id - jdbc_method - name @@ -8435,6 +8490,9 @@ components: jdbc_method: type: string example: mariadb + default: + type: boolean + example: false LdCreatorDto: required: - '@type' @@ -8528,13 +8586,14 @@ components: example: 1 ContainerBriefDto: required: + - count - created - hash - id - image - internal_name - name - - running + - quota type: object properties: id: @@ -8548,9 +8607,14 @@ components: example: Air Quality image: $ref: '#/components/schemas/ImageBriefDto' - running: - type: boolean - example: true + quota: + type: integer + format: int32 + example: 50 + count: + type: integer + format: int32 + example: 10 created: type: string format: date-time @@ -8603,6 +8667,9 @@ components: uiPort: type: integer format: int32 + quota: + type: integer + format: int32 uiAdditionalFlags: type: string databases: @@ -8642,10 +8709,8 @@ components: defaultPort: type: integer format: int32 - dateFormats: - type: array - items: - $ref: '#/components/schemas/ContainerImageDate' + isDefault: + type: boolean containers: type: array items: @@ -8656,28 +8721,10 @@ components: lastModified: type: string format: date-time - ContainerImageDate: - type: object - properties: - id: - type: integer - format: int64 - iid: - type: integer - format: int64 - image: - $ref: '#/components/schemas/ContainerImage' - example: - type: string - hasTime: - type: boolean - databaseFormat: - type: string - unixFormat: - type: string - createdAt: - type: string - format: date-time + dataTypes: + type: array + items: + $ref: '#/components/schemas/DataType' Creator: type: object properties: @@ -8726,6 +8773,50 @@ components: type: string ieeeName: type: string + DataType: + type: object + properties: + id: + type: integer + format: int64 + displayName: + type: string + value: + type: string + sizeMin: + type: integer + format: int32 + sizeMax: + type: integer + format: int32 + sizeDefault: + type: integer + format: int32 + sizeRequired: + type: boolean + documentation: + type: string + typeHint: + type: string + dataHint: + type: string + quoted: + type: boolean + buildable: + type: boolean + image: + $ref: '#/components/schemas/ContainerImage' + dmin: + type: integer + format: int32 + dmax: + type: integer + format: int32 + ddefault: + type: integer + format: int32 + drequired: + type: boolean Database: type: object properties: @@ -9725,14 +9816,10 @@ components: id: type: integer format: int64 - dateFormat: - $ref: '#/components/schemas/ContainerImageDate' table: $ref: '#/components/schemas/Table' name: type: string - autoGenerated: - type: boolean internalName: type: string description: @@ -9759,6 +9846,7 @@ components: - TableColumnType.LONGBLOB - TableColumnType.ENUM - TableColumnType.SET + - TableColumnType.SERIAL - TableColumnType.BIT - TableColumnType.TINYINT - TableColumnType.BOOL @@ -9944,8 +10032,6 @@ components: id: type: integer format: int64 - dateFormat: - $ref: '#/components/schemas/ContainerImageDate' view: $ref: '#/components/schemas/View' name: @@ -9971,6 +10057,7 @@ components: - TableColumnType.LONGBLOB - TableColumnType.ENUM - TableColumnType.SET + - TableColumnType.SERIAL - TableColumnType.BIT - TableColumnType.TINYINT - TableColumnType.BOOL diff --git a/.docs/.swagger/swagger-generate.sh b/.docs/.swagger/swagger-generate.sh index c293e6c5cf19a3b78b75de21e06faadbadeefdd4..8ea2981243601c51fa17f75570f38656cb301ff5 100644 --- a/.docs/.swagger/swagger-generate.sh +++ b/.docs/.swagger/swagger-generate.sh @@ -6,6 +6,8 @@ services[9093]=data services[9099]=metadata services[3305]=sidecar +# requires https://github.com/mikefarah/yq/ -> v4.44.3 + function retrieve () { if [[ "$2" == analyse ]] || [[ "$2" == search ]] || [[ "$2" == sidecar ]]; then echo "... retrieve json api from localhost:$1" diff --git a/.docs/api/auth-service.md b/.docs/api/auth-service.md index 40ad6d8fd54825245574e578bff4c9fd7de1b463..7b59ca1567e31b5e997baca36c4e3bbcce9f7650 100644 --- a/.docs/api/auth-service.md +++ b/.docs/api/auth-service.md @@ -6,10 +6,10 @@ author: Martin Weise !!! debug "Debug Information" - Image: [`quay.io/keycloak/keycloak:24.0`](quay.io/keycloak/keycloak) + Image: [`docker.io/bitnami/keycloak:26.0.0-debian-12-r1`](https://hub.docker.com/r/bitnami/keycloak) * Ports: 8080/tcp - * UI: `http://<hostname>/api/auth/` + * UI: `http://<hostname>:8080/` ## Overview diff --git a/.docs/api/broker-service.md b/.docs/api/broker-service.md index f2f684c4a944f4e726a53f4d050bb19b2f368a8d..41e2dc10b15ccd137a934cd9c162c85b32dffc22 100644 --- a/.docs/api/broker-service.md +++ b/.docs/api/broker-service.md @@ -11,7 +11,7 @@ author: Martin Weise * Ports: 5672/tcp, 15672/tcp, 15692/tcp * AMQP: `amqp://<hostname>:5672` * Prometheus: `http://<hostname>:15692/metrics` - * Management: `http://<hostname>/admin/broker` + * Management: `http://<hostname>:15672` ## Overview @@ -19,6 +19,13 @@ It holds exchanges and topics responsible for holding AMQP messages for later co use [RabbitMQ](https://www.rabbitmq.com/) in the implementation. By default, the endpoint listens to the insecure port `5672` for incoming AMQP tuples and insecure port `15672` for the management UI. +## Supported Protocols + +* AMQP (v0.9.1, v1.0), see [RabbitMQ docs](https://www.rabbitmq.com/docs/next/amqp). +* MQTT (v3.1, v3.1.1, v5), see [RabbitMQ docs](https://www.rabbitmq.com/docs/mqtt). + +## Authentication + The default configuration allows any user in the `cn=system,ou=users,dc=dbrepo,dc=at` from the [Identity Service](../identity-service) to access the Broker Service as user with `administrator` role, i.e. the `cn=admin,dc=dbrepo,dc=at` user that is created by default. @@ -28,6 +35,8 @@ The Broker Service allows two ways of authentication for AMQP tuples: 1. LDAP 2. Plain (RabbitMQ's internal authentication) +## Architecture + The queue architecture of the Broker Service is very simple. There is only one durable, topic exchange `dbrepo` and one quorum queue `dbrepo`, connected with a binding of `dbrepo.#` which routes all tuples with routing key prefix `dbrepo.` to this queue. diff --git a/.docs/api/dashboard-service.md b/.docs/api/dashboard-service.md new file mode 100644 index 0000000000000000000000000000000000000000..96db8260212b1b95081732f1fa386a0b92e2e4bf --- /dev/null +++ b/.docs/api/dashboard-service.md @@ -0,0 +1,30 @@ +--- +author: Martin Weise +--- + +## tl;dr + +!!! debug "Debug Information" + + Image: [`docker.io/bitnami/grafana:10.4.9-debian-12-r0`](https://hub.docker.com/r/bitnami/grafana) + + * Ports: `http://<hostname>/dashboard` + * Prometheus: `http://<hostname>/dashboard/prometheus` + +## Overview + +The Dashboard Service is visualizing the status of DBRepo with charts. The default dashboard provisioner located in +`/etc/grafana/provisioning/dashboards/provider.yaml` checks for new `JSON` dashboard files in `/app/dashboards` every 10 +seconds and makes the available in the Dashboard Service. + +## Limitations + +!!! question "Do you miss functionality? Do these limitations affect you?" + + We strongly encourage you to help us implement it as we are welcoming contributors to open-source software and get + in [contact](../../contact) with us, we happily answer requests for collaboration with attached CV and your programming + experience! + +## Security + +(none) diff --git a/.docs/api/data-db.md b/.docs/api/data-db.md index 648640bb4c85413a7f5afbf65d1649a6e1706c3c..d5ba8d8361351ec7c52d2428f5e1304a64c6791e 100644 --- a/.docs/api/data-db.md +++ b/.docs/api/data-db.md @@ -4,7 +4,7 @@ author: Martin Weise !!! debug "Debug Information" - Image: [`docker.io/bitnami/mariadb:11.1.3-debian-11-r6`](https://hub.docker.com/r/bitnami/mariadb) + Image: [`docker.io/bitnami/mariadb-galera:11.1.3-debian-11-r8`](https://hub.docker.com/r/bitnami/mariadb-galera) * Ports: 3306/tcp * JDBC: `jdbc://mariadb:<hostname>:3306` diff --git a/.docs/api/gateway-service.md b/.docs/api/gateway-service.md index 26ad76f092c599fbb865648577eba7b1a283ba72..9a44f9635b32ecc0d238ed1c1a0e918157ecd046 100644 --- a/.docs/api/gateway-service.md +++ b/.docs/api/gateway-service.md @@ -60,6 +60,40 @@ services: ... ``` +## Monitoring (Optional) + +By default the Gateway Service is not monitored. You need to add the following to the `docker-compose.yml` file. + +```yaml title="docker-compose.yml" +services: + ... + dbrepo-gateway-service-sidecar: + restart: "no" + container_name: dbrepo-gateway-service-sidecar + hostname: dbrepo-gateway-service-sidecar + image: docker.io/nginx/nginx-prometheus-exporter:1.3.0 + command: + - "-nginx.scrape-uri=http://gateway-service/basic_status" + ports: + - "9113:9113" + depends_on: + dbrepo-gateway-service: + condition: service_started + logging: + driver: json-file +``` + +Then, uncomment the scrape config from the `prometheus.yml` file. + +```yaml title="prometheus.yml" +scrape_configs: + ... + - job_name: 'gateway scrape' + metrics_path: '/metrics' + static_configs: + - targets: ['dbrepo-gateway-service-sidecar:9113'] +``` + ## Limitations (none relevant to DBRepo) diff --git a/.docs/api/metadata-db.md b/.docs/api/metadata-db.md index 4336c7666c012caf5b7f2b8f6979a77d049c9643..61a56ed1ac4f50ae2dcfd4b66e35f317f5bb9ded 100644 --- a/.docs/api/metadata-db.md +++ b/.docs/api/metadata-db.md @@ -4,7 +4,7 @@ author: Martin Weise !!! debug "Debug Information" - Image: [`docker.io/bitnami/mariadb:11.1.3-debian-11-r6`](https://hub.docker.com/r/bitnami/mariadb) + Image: [`docker.io/bitnami/mariadb-galera:11.1.3-debian-11-r8`](https://hub.docker.com/r/bitnami/mariadb-galera) * Ports: 3306/tcp * JDBC: `jdbc://mariadb:<hostname>:3306` diff --git a/.docs/api/metric-db.md b/.docs/api/metric-db.md new file mode 100644 index 0000000000000000000000000000000000000000..8ac9b611d99544eba5ee6738c416b12f8c2a1d47 --- /dev/null +++ b/.docs/api/metric-db.md @@ -0,0 +1,155 @@ +--- +author: Martin Weise +--- + +## tl;dr + +!!! debug "Debug Information" + + Image: [`bitnami/prometheus:2.54.1-debian-12-r4`](https://hub.docker.com/r/bitnami/prometheus) + +## Overview + +The Metric Database is responsible for saving time-series data for the [Dashboard Service](../../api/dashboard-service). + +## Metrics + +## Analyse Service + +| **Metric** | **Description** | +|-----------------------------|---------------------------------------------| +| `dbrepo_analyse_datatypes` | Time needed to analyse datatypes of dataset | +| `dbrepo_analyse_keys` | Time needed to analyse keys of dataset | +| `dbrepo_analyse_table_stat` | Time needed to analyse table statistics | +| `dbrepo_analyse_table_stat` | Time needed to analyse table statistics | + +## Auth Service + +See [Keycloak documentation](https://www.keycloak.org/server/configuration-metrics). + +## Broker Service + +See [RabbitMQ documentation](https://www.rabbitmq.com/docs/prometheus). + +## Databases + +See [MariaDB Galera documentation](https://galeracluster.com/documentation/html_docs_20210213-1355-master/documentation/galera-manager-monitoring-clusters.html). + +The [Data Database Sidecar](#) metrics are: + +| **Metric** | **Description** | +|---------------------------------|---------------------------------------| +| `dbrepo_sidecar_import_dataset` | Time needed to import dataset from S3 | +| `dbrepo_sidecar_export_dataset` | Time needed to export dataset to S3 | + +## Data Service + +| **Metric** | **Description** | +|-----------------------------|-------------------------------------------| +| `dbrepo_message_receive` | Received AMQP message from Broker Service | +| `dbrepo_subset_create` | Create subset | +| `dbrepo_subset_data` | Retrieved subset data | +| `dbrepo_subset_find` | Find subset | +| `dbrepo_subset_list` | Find subsets | +| `dbrepo_subset_persist` | Persist subset | +| `dbrepo_table_data_create` | Create table data | +| `dbrepo_table_data_delete` | Delete table data | +| `dbrepo_table_data_export` | Export table data | +| `dbrepo_table_data_history` | Find table history | +| `dbrepo_table_data_import` | Import dataset | +| `dbrepo_table_data_list` | Retrieve table data | +| `dbrepo_table_data_update` | Update table data | +| `dbrepo_view_data` | Retrieve view data | +| `dbrepo_view_schema_list` | Find view schemas | + +## Metadata Service + +| **Metric** | **Description** | +|------------------------------------|---------------------------------------------------| +| `dbrepo_database_count` | The total number of managed research databases | +| `dbrepo_view_count` | The total number of available view data sources | +| `dbrepo_subset_count` | The total number of available subset data sources | +| `dbrepo_table_count` | The total number of available table data sources | +| `dbrepo_volume_sum` | The total volume of available research data | +| `dbrepo_user_refresh_token` | Refresh user token | +| `dbrepo_identifier_save` | Save identifier | +| `dbrepo_oai_record_get` | Get the record | +| `dbrepo_access_give` | Give access to some database | +| `dbrepo_ontologies_find` | Find one ontology | +| `dbrepo_database_findall` | List databases | +| `dbrepo_tables_refresh` | Refresh database tables metadata | +| `dbrepo_license_findall` | Get all licenses | +| `dbrepo_user_modify` | Modify user information | +| `dbrepo_container_findall` | Find all containers | +| `dbrepo_maintenance_delete` | Delete maintenance message | +| `dbrepo_maintenance_update` | Update maintenance message | +| `dbrepo_ontologies_create` | Register a new ontology | +| `dbrepo_identifier_delete` | Delete some identifier | +| `dbrepo_oai_identify` | Identify the repository | +| `dbrepo_database_create` | Create database | +| `dbrepo_oai_metadataformats_list` | List the metadata formats | +| `dbrepo_user_password_modify` | Modify user password | +| `dbrepo_semantic_concepts_findall` | List semantic concepts | +| `dbrepo_identifier_retrieve` | Retrieve metadata from identifier | +| `dbrepo_identifier_list` | Find all identifiers | +| `dbrepo_views_findall` | Find all views | +| `dbrepo_identifier_create` | Draft identifier | +| `dbrepo_oai_identifiers_list` | List the identifiers | +| `dbrepo_image_findall` | Find all images | +| `dbrepo_database_visibility` | Update database visibility | +| `dbrepo_container_create` | Create container | +| `dbrepo_views_refresh` | Refresh database views metadata | +| `dbrepo_database_find` | Find some database | +| `dbrepo_access_get` | Check access to some database | +| `dbrepo_identifier_find` | Find some identifier | +| `dbrepo_maintenance_create` | Create maintenance message | +| `dbrepo_container_delete` | Delete some container | +| `dbrepo_ontologies_delete` | Delete an ontology | +| `dbrepo_ontologies_findall` | List all ontologies | +| `dbrepo_user_token` | Obtain user token | +| `dbrepo_view_find` | Find one view | +| `dbrepo_user_create` | Create user | +| `dbrepo_ontologies_update` | Update an ontology | +| `dbrepo_maintenance_findall` | Find maintenance messages | +| `dbrepo_users_list` | Find all users | +| `dbrepo_image_find` | Find some image | +| `dbrepo_user_find` | Get a user info | +| `dbrepo_image_delete` | Delete some image | +| `dbrepo_identifier_publish` | Publish identifier | +| `dbrepo_image_update` | Update some image | +| `dbrepo_view_create` | Create a view | +| `dbrepo_semantic_units_findall` | List semantic units | +| `dbrepo_image_create` | Create image | +| `dbrepo_database_image` | Update database image | +| `dbrepo_view_delete` | Delete one view | +| `dbrepo_database_transfer` | Update database owner | +| `dbrepo_maintenance_find` | Find one maintenance message | +| `dbrepo_access_modify` | Modify access to some database | +| `dbrepo_ontologies_entities_find` | Find entities | +| `dbrepo_access_delete` | Revoke access to some database | +| `dbrepo_container_find` | Find some container | + +## Search Service + +| **Metric** | **Description** | +|---------------------------------|---------------------------------------------------------| +| `dbrepo_search_index_list` | Time needed to list search index | +| `dbrepo_search_type_list` | Time needed to list search types | +| `dbrepo_search_fuzzy` | Time needed to search fuzzy | +| `dbrepo_search_type` | Time needed to search by type | +| `dbrepo_search_update_database` | Time needed to update a database in the search database | +| `dbrepo_search_delete_database` | Time needed to delete a database in the search database | + + + +## Limitations + +!!! question "Do you miss functionality? Do these limitations affect you?" + + We strongly encourage you to help us implement it as we are welcoming contributors to open-source software and get + in [contact](../../contact) with us, we happily answer requests for collaboration with attached CV and your programming + experience! + +## Security + +(none) diff --git a/.docs/api/ui.md b/.docs/api/ui.md index 4ac5c7bad871284cc322bf7be0c8585942f63ea5..d14303aa2cd7b33d48a743353bc6a82c53b0f55c 100644 --- a/.docs/api/ui.md +++ b/.docs/api/ui.md @@ -6,7 +6,7 @@ author: Martin Weise !!! debug "Debug Information" - Image: [`registry.datalab.tuwien.ac.at/dbrepo/ui:1.4.5`](https://hub.docker.com/r/dbrepo/ui) + Image: [`registry.datalab.tuwien.ac.at/dbrepo/ui:1.4.7`](https://hub.docker.com/r/dbrepo/ui) * Ports: 3000/tcp @@ -20,26 +20,67 @@ image as well, in this example we want to mount a custom logo `my_logo.png` into <figcaption>Figure 1: Architecture of the UI microservice</figcaption> </figure> -Text values like the version :material-numeric-2-circle-outline: and title :material-numeric-3-circle-outline: can be -configured as well via the Nuxt runtime configuration through single environment variables or `.env` files - -```yaml title=".env" -NUXT_PUBLIC_TITLE="My overriden title" -NUXT_PUBLIC_LOGO="/app/.output/public/my_logo.png" -... -``` - -To work, you need to mount the `my_logo.png` file into the `dbrepo-ui` container via the `docker-compose.yml` file (or -if you use a Kubernetes deployment via ConfigMap and Volumes). - -```yaml title="docker-compose.yml" -services: - dbrepo-ui: - image: registry.datalab.tuwien.ac.at/dbrepo/ui:1.4.5 - volumes: - - ./my_logo.png:/app/.output/public/my_logo.png - ... -``` +=== "Docker Compose" + + Text values like the version :material-numeric-2-circle-outline: and title :material-numeric-3-circle-outline: can be + configured as well via the Nuxt runtime configuration through single environment variables or `.env` files. + + ```yaml title=".env" + NUXT_PUBLIC_TITLE="My overriden title" + NUXT_PUBLIC_LOGO="/my_logo.png" + NUXT_PUBLIC_ICON="/favicon.ico" + ... + ``` + + To work, you need to mount the `my_logo.png` file into the `dbrepo-ui` container via the `docker-compose.yml` file. + + ```yaml title="docker-compose.yml" + services: + dbrepo-ui: + image: registry.datalab.tuwien.ac.at/dbrepo/ui:1.4.7 + volumes: + - ./my_logo.png:/app/.output/public/my_logo.png + - ./favicon.ico:/app/.output/public/favicon.ico + environment: + ... + ... + ``` + + If you want to override more environment variables, extend the dictionary in `environment:` + +=== "Kubernetes" + + Text values like the version :material-numeric-2-circle-outline: and title :material-numeric-3-circle-outline: can be + configured as well via the Nuxt runtime configuration through setting the variables in the `values.yaml` file. + + ```yaml title="values.yaml" + ui: + public: + logo: "/my_logo.png" + icon: "/favicon.ico" + extraVolumes: + - name: images-map + configMap: + name: ui-config + extraVolumeMounts: + - name: images-map + mountPath: /static/ + ``` + + To work, you need to mount the `my_logo.png` file into the dbrepo-ui deployment via a ConfigMap and Volumes. For this, + encode the files in base64 with `cat my_logo.png | base64`. + + ```yaml title="dbrepo-ui-custom.yaml" + apiVersion: v1 + kind: ConfigMap + metadata: + name: ui-config + binaryData: + my_logo.png: | + <base64> + favicon.ico: | + <base64> + ``` ### Architecture diff --git a/.docs/changelog.md b/.docs/changelog.md new file mode 100644 index 0000000000000000000000000000000000000000..e7f12b284b67d0af3201031cd96c49eda62c2604 --- /dev/null +++ b/.docs/changelog.md @@ -0,0 +1,63 @@ +--- +author: Martin Weise +--- + +## v1.4.7 (2024-10-21) + +[:simple-gitlab: GitLab Release](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/tags/v1.4.7) + +!!! warning "Contains Breaking Changes" + + This release updates the Metadata Database schema which is incompatible to v1.4.6! + +### What's Changed + +#### Features + +* Added `SERIAL` data type to create incrementing key + in [#454](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/issues/454) + +#### Changes + +* Allow anonymous users to create subsets for public databases + in [#449](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/issues/449). +* Show file upload progress + in [#448](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/issues/448). +* Change the Docker image of the Auth Service to Bitnami-maintained similar to Kubernetes deployment with accompanying + Auth Database change to PostgreSQL + in [#455](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/issues/455) + +#### Fixes + +* Multiple UI errors in [#453](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/issues/453). +* Fixed install script.sh + in [#444](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/issues/444) +* No hardcoded data type metadata in UI but instead added it hardcoded (associated with `image_id`) Metadata Database. + +## v1.4.6 (2024-10-11) + +[:simple-gitlab: GitLab Release](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/tags/v1.4.6) + +!!! warning "Contains Breaking Changes" + + This release updates the Metadata Database schema which is incompatible to v1.4.5! + +### What's Changed + +#### Features + +* Added [Dashboard Service](../api/dashboard-service/) and monitoring in default setup. + +#### Changes + +* Show the progress of dataset uploads in the UI + in [#448](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/issues/448) +* Anonymous users are allowed to create (non-persistent) subsets + in [#449](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/issues/449) +* Removed logic that maps `True`, `False` and `null` + +#### Fixes + +* Import of datasets stabilized in the UI + in [#442](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/issues/442) +* Install script in [#444](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/issues/444) \ No newline at end of file diff --git a/.docs/concepts/databases.md b/.docs/concepts/databases.md deleted file mode 100644 index ecf1025b1d8074698df0b7ec673d19beb516de7a..0000000000000000000000000000000000000000 --- a/.docs/concepts/databases.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -author: Martin Weise ---- - -## Relational Database - -DBRepo manages relational databases that store information relations in tables. - -## Query - -A query is the method to interact with a relational database and is used to read/write data or to create/change/delete -schema information e.g. tables. DBRepo uses a query store to store certain (important) queries that generate subsets -to restore the exact same subset at a later point. - -## System Versioning - -DBRepo uses a mechanism offered by SQL:2013 to version tables with the system (=server) time. When inserting a tuple -into a system-versioned table, the database engine maintains invisible `ROW_START` and `ROW_END` timestamp columns to -denote a tuple validity. When deleting a tuple, the database engine actually just marks the tuple as `ROW_END = NOW()` -and does not delete the tuple. - -At a later point in time, the (historic) tuple can still be queried using system versioning. - -## Data Ingest - -<figure markdown> - -<figcaption>Figure 1: Modes of data ingest</figcaption> -</figure> - -More [usage examples](../usage-overview/) include how to ingest datasets, data dumps, live data, etc. - -### Generation of Metadata in DBRepo - -You can generate metadata e.g. UI tbd - -!!! warning "Limitation" - - Only system-versioned tables are considered when generating metadata to tables. If your table is not system-versioned - e.g. a base table, it will not be visible in the UI. \ No newline at end of file diff --git a/.docs/concepts/monitoring.md b/.docs/concepts/monitoring.md index 10a1b331eb895d73368c17bd87e6d96340bcf011..be70ccac4c83f5d152e0206a31cb20e93af71702 100644 --- a/.docs/concepts/monitoring.md +++ b/.docs/concepts/monitoring.md @@ -11,126 +11,19 @@ instance is started. You need can setup Prometheus in a few minutes using a [Docker container](https://prometheus.io/docs/prometheus/latest/installation/). -## Example - -## Analyse Service - -| **Metric** | **Description** | -|-----------------------------|---------------------------------------------| -| `dbrepo_analyse_datatypes` | Time needed to analyse datatypes of dataset | -| `dbrepo_analyse_keys` | Time needed to analyse keys of dataset | -| `dbrepo_analyse_table_stat` | Time needed to analyse table statistics | -| `dbrepo_analyse_table_stat` | Time needed to analyse table statistics | - -## Auth Service - -See [Keycloak documentation](https://www.keycloak.org/server/configuration-metrics). - -## Broker Service - -See [RabbitMQ documentation](https://www.rabbitmq.com/docs/prometheus). - -## Databases - -See [MariaDB Galera documentation](https://galeracluster.com/documentation/html_docs_20210213-1355-master/documentation/galera-manager-monitoring-clusters.html). - -The [Data Database Sidecar](#) metrics are: - -| **Metric** | **Description** | -|---------------------------------|---------------------------------------| -| `dbrepo_sidecar_import_dataset` | Time needed to import dataset from S3 | -| `dbrepo_sidecar_export_dataset` | Time needed to export dataset to S3 | - -## Data Service - -| **Metric** | **Description** | -|-----------------------------|-------------------------------------------| -| `dbrepo_message_receive` | Received AMQP message from Broker Service | -| `dbrepo_subset_create` | Create subset | -| `dbrepo_subset_data` | Retrieved subset data | -| `dbrepo_subset_find` | Find subset | -| `dbrepo_subset_list` | Find subsets | -| `dbrepo_subset_persist` | Persist subset | -| `dbrepo_table_data_create` | Create table data | -| `dbrepo_table_data_delete` | Delete table data | -| `dbrepo_table_data_export` | Export table data | -| `dbrepo_table_data_history` | Find table history | -| `dbrepo_table_data_import` | Import dataset | -| `dbrepo_table_data_list` | Retrieve table data | -| `dbrepo_table_data_update` | Update table data | -| `dbrepo_view_data` | Retrieve view data | -| `dbrepo_view_schema_list` | Find view schemas | - -## Metadata Service - -| **Metric** | **Description** | -|------------------------------------|-----------------------------------| -| `dbrepo_user_refresh_token` | Refresh user token | -| `dbrepo_identifier_save` | Save identifier | -| `dbrepo_oai_record_get` | Get the record | -| `dbrepo_access_give` | Give access to some database | -| `dbrepo_ontologies_find` | Find one ontology | -| `dbrepo_database_findall` | List databases | -| `dbrepo_tables_refresh` | Refresh database tables metadata | -| `dbrepo_license_findall` | Get all licenses | -| `dbrepo_user_modify` | Modify user information | -| `dbrepo_container_findall` | Find all containers | -| `dbrepo_maintenance_delete` | Delete maintenance message | -| `dbrepo_maintenance_update` | Update maintenance message | -| `dbrepo_ontologies_create` | Register a new ontology | -| `dbrepo_identifier_delete` | Delete some identifier | -| `dbrepo_oai_identify` | Identify the repository | -| `dbrepo_database_create` | Create database | -| `dbrepo_oai_metadataformats_list` | List the metadata formats | -| `dbrepo_user_password_modify` | Modify user password | -| `dbrepo_semantic_concepts_findall` | List semantic concepts | -| `dbrepo_identifier_retrieve` | Retrieve metadata from identifier | -| `dbrepo_identifier_list` | Find all identifiers | -| `dbrepo_views_findall` | Find all views | -| `dbrepo_identifier_create` | Draft identifier | -| `dbrepo_oai_identifiers_list` | List the identifiers | -| `dbrepo_image_findall` | Find all images | -| `dbrepo_database_visibility` | Update database visibility | -| `dbrepo_container_create` | Create container | -| `dbrepo_views_refresh` | Refresh database views metadata | -| `dbrepo_database_find` | Find some database | -| `dbrepo_access_get` | Check access to some database | -| `dbrepo_identifier_find` | Find some identifier | -| `dbrepo_maintenance_create` | Create maintenance message | -| `dbrepo_container_delete` | Delete some container | -| `dbrepo_ontologies_delete` | Delete an ontology | -| `dbrepo_ontologies_findall` | List all ontologies | -| `dbrepo_user_token` | Obtain user token | -| `dbrepo_view_find` | Find one view | -| `dbrepo_user_create` | Create user | -| `dbrepo_ontologies_update` | Update an ontology | -| `dbrepo_maintenance_findall` | Find maintenance messages | -| `dbrepo_users_list` | Find all users | -| `dbrepo_image_find` | Find some image | -| `dbrepo_user_find` | Get a user info | -| `dbrepo_image_delete` | Delete some image | -| `dbrepo_identifier_publish` | Publish identifier | -| `dbrepo_image_update` | Update some image | -| `dbrepo_view_create` | Create a view | -| `dbrepo_semantic_units_findall` | List semantic units | -| `dbrepo_image_create` | Create image | -| `dbrepo_database_image` | Update database image | -| `dbrepo_view_delete` | Delete one view | -| `dbrepo_database_transfer` | Update database owner | -| `dbrepo_maintenance_find` | Find one maintenance message | -| `dbrepo_access_modify` | Modify access to some database | -| `dbrepo_ontologies_entities_find` | Find entities | -| `dbrepo_access_delete` | Revoke access to some database | -| `dbrepo_container_find` | Find some container | - -## Search Service - -| **Metric** | **Description** | -|---------------------------------|---------------------------------------------------------| -| `dbrepo_search_index_list` | Time needed to list search index | -| `dbrepo_search_type_list` | Time needed to list search types | -| `dbrepo_search_fuzzy` | Time needed to search fuzzy | -| `dbrepo_search_type` | Time needed to search by type | -| `dbrepo_search_update_database` | Time needed to update a database in the search database | -| `dbrepo_search_delete_database` | Time needed to delete a database in the search database | - +## Dashboards + +<figure markdown> + +<figcaption>Figure 1: DBRepo Dashboard</figcaption> +</figure> + +<figure markdown> + +<figcaption>Figure 2: Database Dashboard (Kubernetes deployment only)</figcaption> +</figure> + +<figure markdown> + +<figcaption>Figure 3: Broker Service Dashboard</figcaption> +</figure> \ No newline at end of file diff --git a/.docs/help.md b/.docs/help.md index eaecbe6b0461a18320f9572bb408728e110281d2..63ede84f973867d044c8438a7dd774fb60b5a39c 100644 --- a/.docs/help.md +++ b/.docs/help.md @@ -9,3 +9,7 @@ The [concepts documentation](../concepts/) is the most complete guide on how to ## API Documentation The [API documentation](../api/) present reference docs for all APIs. + +!!! info "Additional Help" + + [Contact us](../contact) via e-mail. \ No newline at end of file diff --git a/.docs/images/architecture-docker-compose.svg b/.docs/images/architecture-docker-compose.svg index f1f69f41015048f35566e4e30feecd15d40cecf0..090ac2def7a18149a6f58cfde600bc153c5b2e2e 100644 --- a/.docs/images/architecture-docker-compose.svg +++ b/.docs/images/architecture-docker-compose.svg @@ -1,3 +1,3 @@ <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> -<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="890px" height="559px" viewBox="-0.5 -0.5 890 559" style="background-color: rgb(255, 255, 255);"><defs/><rect fill="#ffffff" width="100%" height="100%" x="0" y="0"/><g><g data-cell-id="0"><g data-cell-id="1"><g data-cell-id="45LT9Xtm5jvL1Omwo4Uv-6"><g><path d="M 418.14 90.37 L 418.53 108.53 L 417.78 125.64" fill="none" stroke="#000000" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/><path d="M 418.02 85.12 L 421.67 92.04 L 418.14 90.37 L 414.68 92.19 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 417.55 130.88 L 414.36 123.74 L 417.78 125.64 L 421.35 124.04 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="S3Av5TdVFqS_SrXukbwN-2"><g><ellipse cx="418.5" cy="7.5" rx="7.5" ry="7.5" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><path d="M 418.5 15 L 418.5 40 M 418.5 20 L 403.5 20 M 418.5 20 L 433.5 20 M 418.5 40 L 403.5 60 M 418.5 40 L 433.5 60" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 67px; margin-left: 419px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;">Researcher</div></div></div></foreignObject><image x="388" y="67.5" width="62" height="17" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="V1Wl26Vbpgnno5Lb-wtg-39"><g><path d="M 346.13 152 L 316.37 152" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 351.38 152 L 344.38 155.5 L 346.13 152 L 344.38 148.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 311.12 152 L 318.12 148.5 L 316.37 152 L 318.12 155.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 152px; margin-left: 331px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 9px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">HTTP</div></div></div></foreignObject><image x="319" y="147" width="24" height="13.25" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAAA1CAYAAAC+2+58AAAAAXNSR0IArs4c6QAAA2NJREFUeF7tm81LMlEUxo8pVAs1KltI4KYWSRlBELg1WwRCENUf0Dpo3d6WQdSynRCBQgXtRJdu2hSulFYtRESxMBT7wLiXt3n7mGbm3rnqC+/jTuec507Pb849d+5Mjk6n0yF8+uaAAwD65j0fGAD66z8A9Nl/AACAfjvQ5/G1HvD09ERut1s7nfPzc1pbWxM6vaurK4rFYlpOvV6nkZER/v3m5oYWFhaE9MyC8/k8vb6+dkV3dnaWD//dF6Nzcjqd/O/1+/20tLTE/VtdXSWHw/FrGgDoWMPAygDQc3lubo4SiQTNz8/rQugZgEKhQOvr64YX9f39PTUaDR7j9XppcnLSMP7i4oLe3t66ojs1NaVbATMzMzQ6Oqp7Xq1Wi8rlMpVKpS/Hh4aGKJPJUDgc/pHXMwBm0wk7zkr28vKSh25tbdHZ2ZmVNNMYO7oyUzO7kI6Pj+ng4IBfIOwzMTFBd3d3X6Z59jsAmOCTAfAhmUwmaXNzUxshHo/T3t7elxEBoIsAmPTKygql02k+yuLiIl1fXwOAyNRmpwKY02wq2tnZ4aazVdLz8zMNDAxoEFABXa6A70vzarVKY2NjAGDauf8E2K0Atqj4fD/1+PhIHo8HAHoF4PDwkHZ3d/lww8PD1Gw20QN62QMikQhls1lu+vLystaQPyj82gPYLfXg4KDVC4XHtdttenh40HI+b0VYEbKzXjfSt6NrZwpKpVK0sbGhndrJyQltb29bqwArhpnF/K8AarUaHR0d0f7+Pr28vHCbgsEg3d7eksvlAgA7U1AoFCKfz6d77bElZqVSoWKxSJ+f9I6Pj1Mul6Pp6ekfeViGCi5Dzar++3G2/3N6ekqBQEA3FQAUAmDbzmwTkW1HM+PZNkQ0GjUcAQAEAcg8JzEaAgAA4K8DdpaL/+Iy1Eq/QAWgAlAB/NVEO3d8HxYaPZS3Uo6Ygrr4VgQA6DuAHoAegB6AHmBQBSp6o6UbMStzNGLUO4DX09V7KqQIAEJ2qQ8GAPWeCikCgJBd6oMBQL2nQooAIGSX+mAAUO+pkCIACNmlPhgA1HsqpAgAQnapDwYA9Z4KKf7+73tCMgiWdQAAZJ1TlAcAioyUlQEAWecU5QGAIiNlZQBA1jlFeQCgyEhZGQCQdU5RHgAoMlJW5h0DqhjC399QigAAAABJRU5ErkJggg=="/></switch></g></g></g><g data-cell-id="V1Wl26Vbpgnno5Lb-wtg-40"><g><path d="M 385 172 L 385 200.06 L 243 200.06 L 243 221.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 243 226.88 L 239.5 219.88 L 243 221.63 L 246.5 219.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="V1Wl26Vbpgnno5Lb-wtg-41"><g><path d="M 450 172 L 450.06 200.06 L 595 200.06 L 595 221.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 595 226.88 L 591.5 219.88 L 595 221.63 L 598.5 219.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="V1Wl26Vbpgnno5Lb-wtg-42"><g><path d="M 417.5 178.37 L 417.5 221.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 417.5 173.12 L 421 180.12 L 417.5 178.37 L 414 180.12 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 417.5 226.88 L 414 219.88 L 417.5 221.63 L 421 219.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 200px; margin-left: 418px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 9px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">HTTP</div></div></div></foreignObject><image x="406" y="195" width="24" height="13.25" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAAA1CAYAAAC+2+58AAAAAXNSR0IArs4c6QAAA2NJREFUeF7tm81LMlEUxo8pVAs1KltI4KYWSRlBELg1WwRCENUf0Dpo3d6WQdSynRCBQgXtRJdu2hSulFYtRESxMBT7wLiXt3n7mGbm3rnqC+/jTuec507Pb849d+5Mjk6n0yF8+uaAAwD65j0fGAD66z8A9Nl/AACAfjvQ5/G1HvD09ERut1s7nfPzc1pbWxM6vaurK4rFYlpOvV6nkZER/v3m5oYWFhaE9MyC8/k8vb6+dkV3dnaWD//dF6Nzcjqd/O/1+/20tLTE/VtdXSWHw/FrGgDoWMPAygDQc3lubo4SiQTNz8/rQugZgEKhQOvr64YX9f39PTUaDR7j9XppcnLSMP7i4oLe3t66ojs1NaVbATMzMzQ6Oqp7Xq1Wi8rlMpVKpS/Hh4aGKJPJUDgc/pHXMwBm0wk7zkr28vKSh25tbdHZ2ZmVNNMYO7oyUzO7kI6Pj+ng4IBfIOwzMTFBd3d3X6Z59jsAmOCTAfAhmUwmaXNzUxshHo/T3t7elxEBoIsAmPTKygql02k+yuLiIl1fXwOAyNRmpwKY02wq2tnZ4aazVdLz8zMNDAxoEFABXa6A70vzarVKY2NjAGDauf8E2K0Atqj4fD/1+PhIHo8HAHoF4PDwkHZ3d/lww8PD1Gw20QN62QMikQhls1lu+vLystaQPyj82gPYLfXg4KDVC4XHtdttenh40HI+b0VYEbKzXjfSt6NrZwpKpVK0sbGhndrJyQltb29bqwArhpnF/K8AarUaHR0d0f7+Pr28vHCbgsEg3d7eksvlAgA7U1AoFCKfz6d77bElZqVSoWKxSJ+f9I6Pj1Mul6Pp6ekfeViGCi5Dzar++3G2/3N6ekqBQEA3FQAUAmDbzmwTkW1HM+PZNkQ0GjUcAQAEAcg8JzEaAgAA4K8DdpaL/+Iy1Eq/QAWgAlAB/NVEO3d8HxYaPZS3Uo6Ygrr4VgQA6DuAHoAegB6AHmBQBSp6o6UbMStzNGLUO4DX09V7KqQIAEJ2qQ8GAPWeCikCgJBd6oMBQL2nQooAIGSX+mAAUO+pkCIACNmlPhgA1HsqpAgAQnapDwYA9Z4KKf7+73tCMgiWdQAAZJ1TlAcAioyUlQEAWecU5QGAIiNlZQBA1jlFeQCgyEhZGQCQdU5RHgAoMlJW5h0DqhjC399QigAAAABJRU5ErkJggg=="/></switch></g></g></g><g data-cell-id="V1Wl26Vbpgnno5Lb-wtg-43"><g><path d="M 385 178.37 L 385 200.06 L 332.06 200.06 L 332.06 294.06 L 245 294.06 L 245 317.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 385 173.12 L 388.5 180.12 L 385 178.37 L 381.5 180.12 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 245 322.88 L 241.5 315.88 L 245 317.63 L 248.5 315.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g data-cell-id="YJRAzF6yD4Hh-bAvO1PB-19"><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 201px; margin-left: 361px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 9px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">HTTP</div></div></div></foreignObject><image x="349" y="196" width="24" height="13.25" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAAA1CAYAAAC+2+58AAAAAXNSR0IArs4c6QAAA2NJREFUeF7tm81LMlEUxo8pVAs1KltI4KYWSRlBELg1WwRCENUf0Dpo3d6WQdSynRCBQgXtRJdu2hSulFYtRESxMBT7wLiXt3n7mGbm3rnqC+/jTuec507Pb849d+5Mjk6n0yF8+uaAAwD65j0fGAD66z8A9Nl/AACAfjvQ5/G1HvD09ERut1s7nfPzc1pbWxM6vaurK4rFYlpOvV6nkZER/v3m5oYWFhaE9MyC8/k8vb6+dkV3dnaWD//dF6Nzcjqd/O/1+/20tLTE/VtdXSWHw/FrGgDoWMPAygDQc3lubo4SiQTNz8/rQugZgEKhQOvr64YX9f39PTUaDR7j9XppcnLSMP7i4oLe3t66ojs1NaVbATMzMzQ6Oqp7Xq1Wi8rlMpVKpS/Hh4aGKJPJUDgc/pHXMwBm0wk7zkr28vKSh25tbdHZ2ZmVNNMYO7oyUzO7kI6Pj+ng4IBfIOwzMTFBd3d3X6Z59jsAmOCTAfAhmUwmaXNzUxshHo/T3t7elxEBoIsAmPTKygql02k+yuLiIl1fXwOAyNRmpwKY02wq2tnZ4aazVdLz8zMNDAxoEFABXa6A70vzarVKY2NjAGDauf8E2K0Atqj4fD/1+PhIHo8HAHoF4PDwkHZ3d/lww8PD1Gw20QN62QMikQhls1lu+vLystaQPyj82gPYLfXg4KDVC4XHtdttenh40HI+b0VYEbKzXjfSt6NrZwpKpVK0sbGhndrJyQltb29bqwArhpnF/K8AarUaHR0d0f7+Pr28vHCbgsEg3d7eksvlAgA7U1AoFCKfz6d77bElZqVSoWKxSJ+f9I6Pj1Mul6Pp6ekfeViGCi5Dzar++3G2/3N6ekqBQEA3FQAUAmDbzmwTkW1HM+PZNkQ0GjUcAQAEAcg8JzEaAgAA4K8DdpaL/+Iy1Eq/QAWgAlAB/NVEO3d8HxYaPZS3Uo6Ygrr4VgQA6DuAHoAegB6AHmBQBSp6o6UbMStzNGLUO4DX09V7KqQIAEJ2qQ8GAPWeCikCgJBd6oMBQL2nQooAIGSX+mAAUO+pkCIACNmlPhgA1HsqpAgAQnapDwYA9Z4KKf7+73tCMgiWdQAAZJ1TlAcAioyUlQEAWecU5QGAIiNlZQBA1jlFeQCgyEhZGQCQdU5RHgAoMlJW5h0DqhjC399QigAAAABJRU5ErkJggg=="/></switch></g></g></g></g><g data-cell-id="V1Wl26Vbpgnno5Lb-wtg-44"><g><path d="M 488.87 152 L 523.63 152" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 483.62 152 L 490.62 148.5 L 488.87 152 L 490.62 155.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 528.88 152 L 521.88 155.5 L 523.63 152 L 521.88 148.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 152px; margin-left: 506px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 9px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">S3</div></div></div></foreignObject><image x="500.5" y="147" width="11" height="13.25" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="V1Wl26Vbpgnno5Lb-wtg-45"><g><path d="M 450.01 178.37 L 450.06 200.06 L 508.06 200.06 L 508.06 294.06 L 595 294.06 L 595 317.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 450 173.12 L 453.52 180.11 L 450.01 178.37 L 446.52 180.13 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 595 322.88 L 591.5 315.88 L 595 317.63 L 598.5 315.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g data-cell-id="YJRAzF6yD4Hh-bAvO1PB-18"><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 200px; margin-left: 461px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 9px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">HTTP</div></div></div></foreignObject><image x="449" y="195" width="24" height="13.25" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAAA1CAYAAAC+2+58AAAAAXNSR0IArs4c6QAAA2NJREFUeF7tm81LMlEUxo8pVAs1KltI4KYWSRlBELg1WwRCENUf0Dpo3d6WQdSynRCBQgXtRJdu2hSulFYtRESxMBT7wLiXt3n7mGbm3rnqC+/jTuec507Pb849d+5Mjk6n0yF8+uaAAwD65j0fGAD66z8A9Nl/AACAfjvQ5/G1HvD09ERut1s7nfPzc1pbWxM6vaurK4rFYlpOvV6nkZER/v3m5oYWFhaE9MyC8/k8vb6+dkV3dnaWD//dF6Nzcjqd/O/1+/20tLTE/VtdXSWHw/FrGgDoWMPAygDQc3lubo4SiQTNz8/rQugZgEKhQOvr64YX9f39PTUaDR7j9XppcnLSMP7i4oLe3t66ojs1NaVbATMzMzQ6Oqp7Xq1Wi8rlMpVKpS/Hh4aGKJPJUDgc/pHXMwBm0wk7zkr28vKSh25tbdHZ2ZmVNNMYO7oyUzO7kI6Pj+ng4IBfIOwzMTFBd3d3X6Z59jsAmOCTAfAhmUwmaXNzUxshHo/T3t7elxEBoIsAmPTKygql02k+yuLiIl1fXwOAyNRmpwKY02wq2tnZ4aazVdLz8zMNDAxoEFABXa6A70vzarVKY2NjAGDauf8E2K0Atqj4fD/1+PhIHo8HAHoF4PDwkHZ3d/lww8PD1Gw20QN62QMikQhls1lu+vLystaQPyj82gPYLfXg4KDVC4XHtdttenh40HI+b0VYEbKzXjfSt6NrZwpKpVK0sbGhndrJyQltb29bqwArhpnF/K8AarUaHR0d0f7+Pr28vHCbgsEg3d7eksvlAgA7U1AoFCKfz6d77bElZqVSoWKxSJ+f9I6Pj1Mul6Pp6ekfeViGCi5Dzar++3G2/3N6ekqBQEA3FQAUAmDbzmwTkW1HM+PZNkQ0GjUcAQAEAcg8JzEaAgAA4K8DdpaL/+Iy1Eq/QAWgAlAB/NVEO3d8HxYaPZS3Uo6Ygrr4VgQA6DuAHoAegB6AHmBQBSp6o6UbMStzNGLUO4DX09V7KqQIAEJ2qQ8GAPWeCikCgJBd6oMBQL2nQooAIGSX+mAAUO+pkCIACNmlPhgA1HsqpAgAQnapDwYA9Z4KKf7+73tCMgiWdQAAZJ1TlAcAioyUlQEAWecU5QGAIiNlZQBA1jlFeQCgyEhZGQCQdU5RHgAoMlJW5h0DqhjC399QigAAAABJRU5ErkJggg=="/></switch></g></g></g></g><g data-cell-id="CohMdi7D_fRk0dSxzjYi-1"><g><rect x="352.5" y="132" width="130" height="40" rx="6" ry="6" fill="#e6e6e6" stroke="#000000" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 128px; height: 1px; padding-top: 152px; margin-left: 354px;"><div data-drawio-colors="color: #000000; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Gateway Service<br />(NGINX)</div></div></div></foreignObject><image x="354" y="138" width="128" height="32" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="iy0HhJzZLXsiPmpU2ukH-9"><g><path d="M 482.5 248 L 496.06 248.06 L 496.06 203.06 C 499.96 203.06 499.96 197.06 496.06 197.06 L 496.06 197.06 L 496.06 189 L 595 189 L 595 178.37" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 595 173.12 L 598.5 180.12 L 595 178.37 L 591.5 180.12 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g data-cell-id="iy0HhJzZLXsiPmpU2ukH-10"><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 190px; margin-left: 524px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">S3</div></div></div></foreignObject><image x="517.5" y="184" width="13" height="15.75" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADQAAAA/CAYAAACvv+soAAAAAXNSR0IArs4c6QAAByxJREFUaEPtmXWIVVsUxr8xETsRFVGxu7AVu0XBwhYsDMRARbEwUAxEMLGx/lDs7lZsMbFbwe52Hr8N57xz7tyZe6733XnDe+cDEe7Ze6+9+lt7YmJjY2P1H0KMr1AS96bvoSTuIPke8j2UyBb4/4Xct2/ftHv3bh08eFBXrlzR7du39f79e3348EExMTFKmzatMmXKpAIFCqho0aKqW7euGjRooPTp0/+Rb549e6bVq1fr6NGjunz5sl69eqXPnz8rQ4YMypo1q8qUKaMaNWqoY8eOyp49exwZ8XqIC0+dOlVz5swxCoQDlOndu7fGjx+vdOnSedr69u1bjRw5UosXL9bPnz9D7kmZMqUGDBigiRMnGqNaCKoQnmjSpIkeP34c8uCEFhQqVEi7du0y3ksId+/eNV7l/3BRtmxZ7d+/X1myZDFb4yh0//59lStXTljMiQoVKqhFixYqVaqU8ubNayz/69cvvXv3zoQhIbJhwwa9fv3atQ+lTp8+bcIyGPA+l7p3757rc/369dW8eXMVLlxYadKkMedevHhRa9as0Z07d+Ks3bt3b3CFGjZsKOsjK3LlyqUVK1YIAaHw6dMnjRs3TjNnznQtHThwoGbPnh10O2Ezd+5c+xt5sm7dOtWpUyfoesJx+PDhmjVrluv71q1bjQFcHsLSWNQCljl37pyKFSsWShfX99GjR2vy5Mn2bylSpNCjR4+UM2dO1zqiIHfu3CbpQbJkyYynq1WrFlIeKUE4W+jUqZNWrVrlVmjevHnq37+/vahz585auXJlyMMDF/z48cNUPGdO4LUhQ4a4lq5fv15t27a1f2vZsqU2bdrkSd6ePXvUqFEjey3yrl+/7lZo1KhRmjJlir1oxowZGjp0qCcBgYuIdQSULFnS5B25gKecIOeWLl1q8oPyTJXr3r27J3kvXrxQjhw57LUUBc5whdyIESM0bdo0e9GECRM0ZswYTwISexFGIN8s5MmTx4S1SyESd9CgQfai6tWr69ixY4l9V0/yDh8+rNq1a9trKfuEoUshOnPp0qVdB5LchGJSA/m2ZcsW+1oLFy40zTxOH6JcHjp0yHV/km/SpEmqWLHiv64XBWfYsGGuNkCenj17VqlTp46r0M2bN1W1atU4DRJNihQpombNmqlevXqGT8Gvog2aNzTs1q1bhk8uWrTINHILtBm4Zv78+c1PQakPvadNmzaCNcQHegbVC8Vq1apl/gX2mUiUhT1cunQp3iNgKoQYjdxp2HjJKZTGIqcfP370dDcoEx6ktwTmoqcDHIviUyhz5szq16+fBg8e7Kpy1taQ89CbN2+0du1aw9OOHDkiYtgLqDq0AcLzTxDKQ3BDDAcrgVt6Vsh5GTwFNeHf8ePHDen8+vVrgvft0qWLiXsSNhxs3LjRNMrfv3+b8eXJkyeGhiGX3yxAz5YvX6527drFn0NeBX///l1nzpwxCkJo6Vn8FoimTZtq27ZtZiCMFChGs1+2bJl9FPnM+fC7kCEXzgWwKAMa9IkcdAKe2Ldv33COS3AtjIaQtkBBgjv+owpZhz99+tSMG3A5Cwx5gXNMpNrBZE6cOGEfg9eiohASKLkkthP0koIFC0aqh71//vz5puJZ6Nq1a/QUQggMGyUskGdeBkWvGnMeA6kFHmhcHqIk855w/vx5UZ1SpUrl9eyg62rWrOkityQufQrAAMg1XnmeP3+uly9fat++feLxwyt27twpCo4FWoStUOPGjQ21sKoUZbNVq1Zezw66jrxxvhVQdsuXL2+vhfJTtSycOnVKlStX9iyT0Z0R3kKHDh3+Vqhnz55asmSJ/ZFOzwUChzKv0tjrJLP0IYYy53sdvYP3Awt9+vTRggULvIoQToDHWcDjtocIMy7g/INet27djJLJkyf3LISFlGxmFV5pLLRu3VqM3E4QgrwkWcB4NM5KlSqFlBc4grMBea4c6tGjhxmJnahSpYqmT59uSKgX7Nixw/AsWLsFvIPHSpQo4TqCPMKITsWZQnk5db4XBMrdvHmzMLaz11Ec8JZLoS9fvpgq5Kzt1mHQdL4VL15cxD5sF29Chxh9KSYc+PDhQ5d8ujhh1KtXr6D2uHDhgugnyHaClx+8x+MHspBz7do1oQyUywnY9smTJ83d4vQhNtLReRKKFAjC44RbQjhw4ICYQL2y+kBleCmy3vHibazUeKZUGHa4yJgxo2hyY8eOVbZs2Txtf/DggXiQ5MHQ6x/mKQo013z58tkyQjIFwmn79u3GzTdu3BCCsSSvpPQMwgEqT0gy8NF7iOc/7WHwMcYVSvjVq1fN5Iw8HuSZhXj0ZKJu3769maADEVIhT+ZNQot8hZKQM4JexfeQ76FEtoAfcols8LDF+R4K22SJvMH3UCIbPGxxkT9lhi0yuht8haJr38hP9z0UuQ2je4LvoejaN/LTfQ9FbsPonuB7KLr2jfz0vwDyX80tMaASYwAAAABJRU5ErkJggg=="/></switch></g></g></g></g><g data-cell-id="13tBXMPt0xomx7MP2VuM-1"><g><rect x="352.5" y="228" width="130" height="40" rx="6" ry="6" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 128px; height: 1px; padding-top: 248px; margin-left: 354px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Analyse Service</div></div></div></foreignObject><image x="354" y="241.5" width="128" height="17" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="V1Wl26Vbpgnno5Lb-wtg-46"><g><path d="M 245 370.37 L 245 397.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 245 365.12 L 248.5 372.12 L 245 370.37 L 241.5 372.12 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 245 402.88 L 241.5 395.88 L 245 397.63 L 248.5 395.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="O_ELZSFbvl3Butg3bv_j-1"><g><rect x="180" y="324" width="130" height="40" rx="6" ry="6" fill="#e6e6e6" stroke="#000000" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 128px; height: 1px; padding-top: 344px; margin-left: 181px;"><div data-drawio-colors="color: #000000; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Authentication Service<br />(Keycloak)</div></div></div></foreignObject><image x="181" y="330" width="128" height="32" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAgAAAACACAYAAAB9V9ELAAAAAXNSR0IArs4c6QAAIABJREFUeF7tnQf8f99cx9+yI6PIKJtkVMqsiCJkZotCRjJS0rDz1zCzk+zK3iraIWRFySYaZlGKKEp1n9zj8f6/nXvPOXd9f/f7eb0fj9+D//dzxzmvc+45r/c8pzCJEBACQkAICAEhcHAInOLgeqwOCwEhIASEgBAQAiYCoEkgBISAEBACQuAAERABOMBBV5eFgBAQAkJACIgAaA4IASEgBISAEDhABEQADnDQ1WUhIASEgBAQAiIAmgNCQAgIASEgBA4QARGAAxx0dVkICAEhIASEgAiA5oAQEAJCQAgIgQNEQARg+0G/q5k91r32zWZ2me2bcVBvPJ2Z/Wfo8beb2V8fFAp1nX1wh9XPu0tf2uH0g3W36iohcOQIXNPMft+14t/N7CxH3qoTtAEiANsPjAjA9piLANRjLgJQj1XLlV9rZpcwswuY2df0/77KzD5jZv9hZv9oZu83s78zs/9rebCuPRkCIgANE+IoCcCPmtlTQ1v/18zOb2YfbOjD3i4VAdh+xEQA6jEXAajHqnTlpczslmZ2o37jL13P758wsz/prv9NM/uDmht0jQjA1DlwlATgDWZ2uUzDH9gx4F+Y2qEjuA8M72tmpzSzf+vMTY8qtEEEYJlBurVbVMEc7IfkkAlA6/wUAZg/P89rZg8zs5vOfNRfdVaBHzGzd8x8ziHdLgtAw2gfFQHA//qWgXZ+2MzOZ2ZfaOjHUV56cfeB/kNvwRhrjwjAMqP1T2b29f2jMKv+feGx0Q/46R3NsTmItc5PyBL/kvx3b6ae04ZDupd4npe5uZnrO2Z//rH+ntHMTj8CELEr1zGzPzskEGf09VQ9pukRuFOIA5BkEDgqAvBEM7uDaw8bJ5t+EoKOCD7ag9zOzJ7cN1QEYJsRu5CZ/a17VQ0B2KZlJ95bWufnideD/bToXGb2djPD3+8Flybuzj/qrALvzFirILK4C67bEdnbhA2M53yqDxR+336gUEv3gMBREIAzmdlHOhPZGXqAPtn5vdCKn+kAI4rzWnsA0Mye0gXw3FYEYNPRwiz6WyIAVZi3zs+qh+qiLALP7wjAjcMvD+pdmlhSauTsnRXx6Zn1b09rYk0/dc0JgMBREIBoAifY5S7dv487UxjBgBc0MzTqE11g9BcTAdh0mB5vZncSAajCvHV+Vj1UF30FAmczs4+aGSboJMxT1rZWObWZ/aGZfW+48QpmRuyURAgsgsBREIC3mdklXeuv3QUDvtzMXmhmN3R//+U+uG6Rjq70EPzK/9r78niFXAArAR0eS3AUJtMkcgHkcZ8yP7cZweP3FgL+nuu6he/5PJ2rk5imKXJhM3t3H1yc7v8NM/vxKQ/TPUIgh8DWBOBKZvbnriFo/efuNvr/6VNlXuB+g00TTctvLYL5jAjxJJhAb9/wgCd0TP6O7nosFPjlklzNzP644XmP7nx+P+WujxYQGD3MPglpkLgUrmpm39QXsfgvM/uXvnANqUGYvz/b0AZ/KZslvsbv79wuFzEzTI7kJUNkSEH6m177+L3+nTWvOY2Zfc5dSNuSi4c/kyFBKhT/vqMfc7QcIvfxj76mT3saCgxFq6o1ofK+twaCMDcLAGvU9c3sGmZG/AE+W56J+4rc7b/o/v7bPXY1ePlrwIbvgjGB1DAmZ+7xI1AMjNgI3mhmz+59yGPvmDs/52YB0Icf6LVX5jKaMYFu9IM5jB/7FT3pf08lWGvPr8pmjF52j66fD3dXsH6xts2RR/ZWUeIKyARAeeIbrRWyrBiL7+vilL6x/9bBknX3n7v5/Lr+Wyc2wX+/Y88nIPF33QW+UNRZzeye/VxmneEb4XcKSzGHvUCYcJm0CvFhLw43Eej6rv5vc7MALt+3H+vLN/TfOmSO9ZFxeFW/VjG+U2SN9XdKO754z9YEAD//LVxrqYh3t/6/mZiA6gNo2DBe1Ni7vRGAV3cRvt9jZhQFub+Z3dvM2BzHhI/35v1CWgsPixEplpAZNp2SECVPKhOLWqyil7uXBYQxTMI7cOV8W0dknmVmfKQlgdhAviA8Xo6KALB5gdmPVWKGnxbXRK3risUUjL+5BIz7HWsZ7RnSLI+KADDO+LvZcGqERZUN4D4hoHPo3jXnV017S9eQCvyL7iK+0XOUblrp98t2xOEhGRfC0OvIoGEc+E5LEucXytDVzeycPRFmg/OSCMJfdsTh0u4Hxn5KmiRt/CH3HJ5Lf5NMJQBYpR/RK0YlDFBKH9dbqCHpNbL2+lvThq+4ZksCgKaJtnda1wq0Qcy5SdCWEyHgbzBTtK4W2RsBoOgH2nhsd6nPaMTf2bFVSgmXBJzZOKYsSK/vA5LQdscEwoCml4T/T2wE/UOjrRVcQTGQ6igIAFo/bY8LWqkf4EQAK7iNSdwwSs/1v6MFXrFbCHMa9FEQAMbrGeHbru0PeKHVectg7t4151dtW8eug5RhovdyFK4prJ9kJflYhNr+Yf0kZgHiPiTf3Vvs0u9Y77BgYRWA0EZJBOCnO0vjr7of2TixpLVYMkmXhFj5deYnO6XxMe65UwgA3yvW57F0zBweWBohP7RpTLZYf2vH+GTXbUkAMANhXkxCHXbqAXj51t58m/6GloDJlfKYtbI2AUDLTVYKzMJ8NEk+FNgof2eis3gliS6A3+k/qIf2F/CM5/XmfvJXv66zgoDLzboFhjQjL5AnJteYfEvPzP1Hw/Voq7wH0xnto0/kMFO5LJ5NwHtwU3x+5EUs5D7XHvfFn/Z+UBYUcqPRFugf/415DdPkDXrrh3805nBcEF7QMBCIJG4KL5g6ffVIyBHm5iStLgDewfyMJlxMpuBGH3gHPl4WHCw4XkjbwhQ+NG+jv5h7sbIwHiyo9AUrCBkzkCiu99oT1+N6oLRsNN3OnZ+tLgC+Aax0WLCSML4v6c2/pGti/md+0ResepHU0we0OEzcQ7L2/Bp5ddVPWEDi2RJgADnaqqZJrroq3yyWNRQANH3mLesIBJIUUb5DL7/WZ2UNdZq14U3uRxQQSIMnvPSX748NlfoFEDy+Jea1nydgA+GvFa73bgM0cdrvN+BWAoCpn4BLb3UFM/72ys6iR70RfrtoP3dx0Xmh/981sjZutf7WYniy67YiALyHhQCtKslP9GaU2HAml9+AMCtiFq+VtQmAbwdmePyySaYEAbKpQITYpDC33y9jAuf5aNH4vmJkMJuf/yB9+9gM+A0CkYTNiQ2FCT4kBBrhnvFaxEndxQ8YuQcfGT7AJGz4BHgy7jcZOXiHDYRFwLsl2PwhATmBCET/W0nTaiUAMZ0LIobrikU0J9frzPjPCRoEi0ccK+5lMcEP7utefKCP+RgrZvRzvVnXv5/YEqxmQzJlfrYQAIgSftFUkIl2fKxf8Mei1RlbAua8xgXJZC4PxfxsNb9G4Cz+BBaQMi+tbqHiSwYuIGgQAuJjb8gAYW5CFnPCd4EpGyLgBWJOnEZOYhE33sEmSGouhBdNn28/xezQnmQmx6JGbFMSvhlvzi/1PX6XvCdaHVoIAEoRpJNYlST8N+tjjFngd8gL6yDWOy+si/w9ypbrbwm77O9bEYA4KGg3MMKcWZnN59dda2FgaFq1QWB7IwCpqzVZDwRFvjeYWgm6wd+Xk7v3fq30G8z8KsGENzRxoskOVsymxQKfE8zSWCu8cC0WilLAzNNCoCULBtpvzhS5NgG4cs/8fT8wq2PNGBNiK+iHF8ylBAh6wUceiQQaMe6ukrDg+foYMYA03r82AcBnyhxLwjeKJo9ptCQs/NHnzN/YFHKy1fwqtXvsd1x5EOu4rrLeQXgwMzOPamJqWtuBqZ3NPgkxIlihaoIG471sgl5p8G2JVlq+cTZ53sPYe8tb7APBzQRlJ+EQJEhkjPnJ9Z3NGk3fk0asoljNvLQQAErOe6WG4Ej6N7TGpffEPYZ9jD0qxgNsuf62zpcvXr8VAcAUhqaXBK3ZBwP6xqPpsmH4gUaD9BkCY53dIwHApM1GWWMqRKNgkicZYtGMLWQBzSAJvjJ8ZjXC/bgHMH0lQQslaC0nuQW6NtIXEzrRtV4IjMv5uNcmADFQdcwa4dtbizeLFoGCaM0sftzH/9acABddB8wXiNKQH3VNAkAsD5uMJ30l83GcNzEwLAWUHeX8qvk2xq6JxDlei7sDczkxD6/t///cUrUQc6xI3rxOSnWMlh9qN5sX93uL35BlkWC5nKsGX3gpO4q1nc3Vl5rGBcj+UJJIGLFkEtMUyUMtAQArLG70PcnPhDiFoTahiGHtGMO7dj0Yekfr+lvCL/v7FgSA9BOA9ibekkaFzwqTUpIUKFfTyT0SAHx3tLtGiBX4WXchpjpMdlFiyiW/l0zl8RmYmElFSjKmGUQCwPGmvG8soCg9lzREPmgvWCoiKeD3NQkApBM27wNVx7TSiBeR1GjoaEHggVkbV8qY8A3WbP48g7iKSIpwqw3FGqxJANA2Y7luzMPRDz7W9zi/mCvECuQ2xK3mV803WLqGTe1JGYtY7j76jOsAMoB1AEuQjxkqvYvfcRuSrZKEzRziXzuvuC8qaT5Dy7chRwBQYIiBqJFY7wUrEHFHJYntG0rvriUAuOfi+QpYpUvWytROyBUuz/St89/+9Mat198SftnftyAATEwmaBLIAIvW2OSMGiHXsvj5+u9DHd4jAYDJliJJU39jvjG58zFAjGtj0CW+uuifLE0agra4LwnjgMaJ6S5KXKCJRPbnPZTexTO9/5INxucbp/vXJABkVUSTPZo6psETQUhLjG1h7IfqJ6xJAHBZ+dgcynvHgLISZv6gonTtEPHban6V2lz7O98J1jZinbDw1AquNqwDuJMwb9fUQYlWwSkVCLFKcV8SYodyp7XmCMAvhTV+rK9YJnzgH8Sfb2ysDgFYsj56Yj40T2oJwL26tOVfcQ2dsj6O9XPr9bd2fp3surUJACYlAuN8NDW57j5fdqjhmK99xCWaL6CWZG8EoHXhvHO3oGBqTUKBEF9ZMf2dyGw0kSSYtn+4BF74nfmBedmb7IgeRluJEhdoIoP9glJ6NR+4XyiH3D5rEgAWa59ShDUgHuxS6seav5NlEeNm8LtiSs/JmgQAbcdH8+P79q6pGhxYH/CHe9MzftPckdpbza+adrdcQ9AnsQG4QDGT+4Cz0nOImicwmO99zD2IFurnKcQ7HVBWekf6PZJfTOtY5iIByREA+kY2U42wieMG8BlDpftv1RffSc9nT8G6mFMiawlAtESgwftKtDV9Gbtm6/V3UnvXJgCk/HjfPeYuPgCfsjXUcILbyABIguaDO2EsFY1r90YAMP+RKlIrMUhyiADEcrlE0LZsyKk9VLgD9yRDi0tcoNl8fGnUUv9YFHydgqMgADGorSbNstSv0u/4b4lkJvgIjRizIgvvV2didPheIyE5KgJAfIgvYNTq/0+4YK72tRbIFccXG2Wr+VUar7m/01dINKlj/GND9b7k3POpAolFjIDoKPjVSbP0gisqWrJK7SaWI8ZZoYBFq2uOAGBZ9JbC0rv8AVVcyxrDJj8kMfh1LGC6lgBgNfNp6Lg6id9YSrZefye1e20CQFAI/v4kaA21lcLIVcWP7LWDmk1lbwSAFJqYdz82mLUEAL9wi7ZRO4GIP/AlT9N9cYHO5fKPveNEIAAc2Uo8RhJMsWQFrCFEaEM4MGXO+Q6PigBgufJ1KVrMwB5PYga8/xjfOUV1omw1v9YY67FnYt5G+2YesDYO+dIhXJjko/sNAjmWPjqnP7m5lSMAzINS5LxvBzFLPquGmA/cADnlDkKccvHTM4YChPm9lgBE4omrmqyApWTr9XdSu+csPKUXwh4JWPLvqI0KT8/GrOTzwYcC3nxbRAC+hEbMmy6NV+3vuG9w4xzVAr2mCyCaBVsIay1+XIcVBWvMlGpt8T1HRQBIecJKkQSfqi/0VYsH7iQ04ST4vcmUOKr5Vdvuta6DAECyc4FxucC8mJa3ZLvI2Y+BcjkCgBUiBvGOtQOLB1Zg7xrGCoamH4UaBd6dMRSbkO6rJQDRbTKWTj0F063X3yltnKV5lF6IKW9Jk0p6H2lpxAcMiQjAl5CJPvXSeNX+PmQq20pD25IAjKWl1eIVryNLgODGaPZloaWcLqZJKg0SCR41ohMpBiAGbRIQ6F12tfhgqkYDTjKU1rrV/Kpt99rXsSFikveBb/jlCbRkc0mSC6Rcqm0533yOAOCyygUGj7Uj7g/x0LV0L1kRxFAkGSogl36fSgBwm/igwLkYbr3+TmrvWhYAgsZYxGJhmEmNDDcN+QjTZSIAX0KCanO+BgDmLZ8qtMRY+GdstUCvSQCiCwDtFH/tUoLGjynXjwvRz6Qa1uRsn0gEgBoAXoOrKWSVw5GiQb7ozNCRt1vNr6XGeonn5GoKxPK5EALWWi+4rUpnK0xt31IEgLon/hwTgluJAfIF3wgKJi0vpZDzG3NurLhRLQGILoCp83cIx63X30njuRYBiFGbkxo3cBODT1DaUNrIXAKAFubNb0PMlOZNibKOZwGsFQMQSyrjbyaFcC3ZaoFekwBg3fBHN+PCajmpr4QtJlVqWnjh9MMnlm7sf2eBjL7Wo3IBEPRFmmgSqneSodIqRHRTWCXJULbPVvOrtf1rXk9aLJYgv05HTZVrovY9lEK7RFuXIgC0JQaSEgPhc+ljvBOWM1/tMNefWgIQg/SGiOdUzLZefye1cy0CEM16LKS1lfxiRyjOEl0JVBH0Nfj9PZEAoNXFWtdjYMWc2r0SgHhsJmkpZGWsJVst0GsSAE6i9LX10TiYfzUVGmtwxcSIrzxJbWZLup6zyuMpg0dFAOLpbwR1+YDfGjywFBJL4N0hkAhfCjw9Z6v5VdPusWuYL/Sn9pjY0vtisCWVOKnI6SVewzwuFaAqvXfo9yUJQCxgFNdqYr4IjkxSE0NWSwBiml5NfFkLZluvvy1t+/K1axCA3KlYbMAM7lRh0WPxS0KFOD8x/HNhcj6KeKzscK49mJzSyXP8vlcCEOtQ1xxUNHV8uG+rBXpNAkAwWqxxQLR+TW17MMBf6w9EIk/Zp27FCpf4/f3hKCX8c0cIHxUByNVRx0LRUn2OIkaxhsFQf7aaX6UxiL+zhkJayOTBrI1PHnPy2MFZLe8guA4fexJqoaSTQ9PfYi3/sTWr5d25a5ckAJz06tMM8ZvzfTOHyApgLU7kkEwBfiudG1BLAIhZYZySEFeBy6Gmcin3MCa+cBkWaV+jY+v1d9K4rkEAOB4Xs2YSJjB+mzmMOB4iwbMxP+ZObCJFzZu6h05lywEWT7raMwHIaYtjVeMmTSB301YL9JoEIFcKuCU4KFZTww9IBcsk+Pk5GjVJbRlUrqegDIulN5fz96MiABS1iSdKcmT02CmAcY5FDZCiQMQ55NLBtppfU76DeKYBPnmClVvOus+9l/og8ejrXGnqWHWOCHfW3FLNlCl9XZIA8P6o3KX5jBKHMpdkKD009qGWAMRURJ6TO7xrCCNqnGCRGGrf1uvvlLFcPAsAVoQ5yp89P6UsZewM6UawQXJmkwxFo5NC4xkyH0PtYStRQ+NdLRYAUlviAh37slUMAO+NPjbiG/wZC6VJQ9EZCBRaMdG4aKxDB5dstUDnCACaBEE9Q9JyHDAWI2I7kmA5YROvWUw55c/XuYhzJ7qncDf50/3GxiOeAZGuHVu0YoxKzfysPQ6YwCyw8eV/KV8LWa+RXEAk39+tB27ean7VtD1eQ+GieEjWEuseblPvtmMOknPvswBoC2PAWPjzVm4fTt4r9QtCh4uK7xxihxs3dwLr0gQgVt9MlWKjK5by8K8udaKhDkBu/tYeT8x6QhCsL8qVO89ly/W3ApqvvGRpC0DUgHhjiwl1rBN8UDw/CR8BEz+ahEgZiUer1gTF5A43KRGAWOkQxg/5GTODbkkAok+b/tRgwXWY3mC5RB0nIU/e/7cfr60WaDJLYhRwSfNsIQA5zWCo9oHvP5HX+BH9NxXzqGN1S8gUmlpJU0TTYHHievriSzOPlVGdMj9rCQB9j+d8ECuBG4XKdSXJRbiTDhhjHNJztppfpXbnfscUTGqyz4rgOuJJ8NfXkEf/XDYnLJk+IJXfxzao6NNG8cHiBzEoCRsZuPvS60PpdksTAEz9KI2JvKBsoMXT/tP0Da85Pyb1sdYCkJu/mP8pbx0DdSN+0XKFdZuxj7UQtlx/S2Oc/X1pAhBTekrnlbc0OhdbgDaLVusFKwSR0r5ICdohi/FQxSyeg4kJHy5anNfKxiwAuROlSsdibkkA+IBYjH11MQgT2gFnAwwJmyzmN699UBMc89zQaW9bLdBojvTBaztoLpjqh6SFAPCM6FPlb3z05LnnAgJZNLAceP8/GhTauRf8xEQHexkrQYrZH18ygYN8q7jW8C36zIRcUFh6/pT52UIA+NY4IZJqdEmIeYBkDpEA+kEhJAL9fPBfKVZnq/nVsib5a+kzLp5Y3wE3EBk4kOfSoVK4PyB0mPR9hgXvof+4BIYq7mEF49v01lfWO0pqD50VwXPZ0MHenydCBVbenyOmSxMA2uDPleD7Yn74mLGWKpMtBACLMqXY/ZHAkGyy2HJnGzC2EFescX7vZF3wB2OlebHl+jtp3i5JAHIBVHOD/2KnWFTYhJK8pispybGLUWKtaX4nQIOa03wMWA9g7Zh2OQAi1YSGYWP+wpSZZKxONRslH7XHETZIHAQfPhOMd/hT8bYkAOkDf11YGPg7GxFV11jAYdtsktQpx9RGJTYfeMT1JV/4lgt0JJpYXCA0aDEQA/LssRilGJFWAoCZlcUU7cQL5T1ZyBlbSAjuHkz+vpId16MJULY1Ht3LbzFDhr9BONgQaS9ziediUcCcnso5syARP8CZDp6Y4TfHMsa3QEU2fzLglPnZQgBoOxYTFnDIShIWcdrJhgj5po2cZIhGilvCf8Pcw0bFNxhr2nvst5xfkxbTPhjwcQOlnZmjjC9zAvMx6wR/Yx1inhEzQE39XHVI1iuIAWM8JrcJaxfXotWSscE/xoK0Qr5tSCSbJQWHPGnB7I8Sg+svJ2sQABQw3D9JwMe7lkrF33w7WwgA99FXlD6vUPB3lFcqExLPwTcJXuwVEC0vrEX4+4fS0sFri/V30pxdkgCwUfrT5lgEWUhL5s2WhqO5oql7yR1Egc+fjc0fLlN6D8QAjYkPwqcYljST6PeN72Ex9B/11gSA9hCdzGT22Q0lPPzvbAo+fS1375YLNGbVhxQ6ADFMC2YrAeDRLDpUAvTaQQ1mbGKQgiFTNlHiEFkfQVx6Lr7Pa/eLd26RT/ezqXgNkL+3zs9WAsA7WHQhRt7qVupT+p0FlL6x6I/JlvOrtu2563BBsplN/dbiM1mXWFdzZDL3frRXSud6QlbbH9ZqaqC8ZOSGNQgAc5YMAIJwo7RakVsJAO+DWKP8+aqLNZixx2BZLll2tlh/a9r7FdcsRQDQNGBK3je5RBBMbDCLJsGAXjvl+FbO3Y7CAo4GEk1pOaDQhNHSIS0wbf8BjPm9eRZ+M7Q6NJycnAgEgHZBxjAno1XW1qBngrPZ+uIcQxNtywWaD5VKZ7nzylP75hIAngOBJFWITTdqCDkcwIno5dJpl8QsMK+izzg+E7cL3xGxA2jRCGZFrDe+el66L0cAWufnFALA+/nOMI1CoGsETRQfOUSupozslvOrpv1j17ChUcQGP3opKHjoOZBEjkVmY2pJreR5WFoYx5a6DATdEXMwVmadZ69BAHgu/cydAYHC5I8/L43NFALAM7FApcO5Su/ASsJ3iVKUvsvSPWuvv6X3Z39figDkomCXCv6LDcdUyseVBI2LhTQ3ECzaBK2xqWN2xNQGiWChxJxLwAls3acuxWptBBT6c89zQOIDxUTOdQx0ygnlY2Kx9trzUVgAfJtZkFik0VQwa0Fc8F2nNmPeps1YDNhkaxefrRdoxpF5h48zmeWYC/gvqa7Ixp20yikWAI8ZLoV0njvvwsKUUgYxq2JpwAUxFB+RmzPcT+QwY0GMBoFYmGIx92IqJuMCq1oubgXCfVLva0fTZDOlHYxZLv+8ZX5OJQCpj/QFjZ7Nh/cyv+gr/UJTAiOCrDBJx2j2sUVs6/k1aUHN3AQemJnx36OUYNqGIDB/Mc8zdvxDgcIfjUUEqw3zeK5ABLBGYdlkLJi3vBdNH42becYaiKKUS6nOvX8tAsChb9HvXlP6N7ZxKgFIz8Gdx/wFM8YKzNgncZNy9DquEbJ5UESnyFrr75S2LJ4GOKkRukkICAEhIASEgBDYFoGlLADbtlpvEwJCQAgIASEgBGYhIAIwCz7dLASEgBAQAkJgnwiIAOxz3NRqISAEhIAQEAKzEBABmAWfbhYCQkAICAEhsE8ERAD2OW5qtRAQAkJACAiBWQiIAMyCTzcLASEgBISAENgnAiIA+xw3tVoICAEhIASEwCwERABmwaebhYAQEAJCQAjsEwERgH2Om1otBISAEBACQmAWAiIAs+DTzUJACAgBISAE9omACMA+x02tFgJCQAgIASEwCwERgFnw6WYhIASEgBAQAvtEQARgn+OmVgsBISAEhIAQmIWACMAs+HSzEBACQkAICIF9IiACsM9xU6uFgBAQAkJACMxCQARgFny6WQgIASEgBITAPhEQAdjnuKnVQkAICAEhIARmISACMAs+3SwEhIAQEAJCYJ8IiADsc9zUaiEgBISAEBACsxAQAZgFn24WAkJACAgBIbBPBEQA9jlue2v1BczsDWZ29r7hnzCzy5jZP+ytI2qv/ZKZ3cfh8DIzu84B4XI1M/tj19/PmNkZZ/b/tGb2KjO7fP+cL5jZ9czs5TOfq9uFwCgCIgCaIGsjcGYz+wszu3j/ov82MxbRP1/7xXr+KgiIACxPABioc3VE6i/N7Nz9qH26IxrfbWZvW2UU9VAhYGYiAJoGayLA/EJD/AH3krt2loBfy7z0UWb2k+45Q/noAAAW2klEQVTv/2JmZ5vYuK8ys98ys1uG+59iZncws/+b+FzdZrIArGABSPPqch05fo2Znbr/wz+a2beb2b9q4gmBNRAQAVgDVT0zIfBTZvZIB8cfBDLgkVqKADCnn2RmtwvDACH4UTP7Xw3PLARkAVjHApAG5f6dYnaSG6EXmtmNZ42YbhYCAwiIAGhqrIXAJc3sTWZ2uv4FnzSzb+k08A8PvHApAvBYM8PK4OVZZvYj2vwXGWoRgHUJwKnM7HV9jEwasNua2dMWGT09RAg4BEQANB3WQuC1ZvZd7uF3NrNfH3nZEgTgIWb2c+EdzzOzW5gZgVWS+QiIAKxLABihS5nZm80MVxbyb2Z2kY7YEjwrEQKLISACsBiUepBDgA33me6/391r//+zIgHAbIr51Avm05ub2dh7NXBtCIgArE8AGJHfNLNbuaF5gpndqW2odLUQGEdABEAzZGkESGl6n5mdxz34B7tgppcWXjTHAoDWj/bvhffdpEtZI+tAshwCIgDbEAC+H74jvicEC9a3mtk7lxtKPenQERABOPQZsHz/8VcSbZ/kPWZ2sYrI+6kE4CfM7DGhG2Qe3NDMPr989w7+iSIA2xAAJtpT+8DVNOmIA+D7kgiBRRAQAVgERj3EIfB2M7uE+++htL8I2hQCcPsub/qJIZ31D83s+mb2uQVGhbQsUhi/z8y+sS9kdBoz+7iZ/XMfrMX7/qjwPtIb6V8SrBLf0D+ntZn37LTCB7mb8A+TQ/5fIw+6YI/JNczsQmb29X1wJoGZ7+/rNPx2R5r+pqIxcwkA/m0w/V4zO3+f6kkhHfpB6ida7yv6IjiQx6kCJsyDK/fzkf/+mn6u8K6P9X72PzOzFxTw822YUwgI19gzwnwlaPVuA50Eq79yv0Foz9e3fSouuk8IfBkBEQBNhiURYLF9pXvgZ7vAv3OY2X9UvKSVAJDjT2pfCpTiFX/SLerXbVjMh5p12d6lwCZVI3/fV8cj2yAnX2tmH3HmXK65eyAFNe/hGjYENoYkBFYSYJkT6ig8sHv3j5nZKSte8Pu9n3msQuNUAvBtPXHxNSHGmkSthuf3uP5tRdvTJWc1s1/p00BTPn3pdvLscSN5y9XQPVMJAHOJNFgIZBLiZMhOGatLQRGt73T33M++VItBIgRmIyACMBtCPcAhQIEfvxm9qKtkdqNKhFoIAHnRzwmbGsTjWmb2n5XvG7rs1p22/+RukSUdq1UI1LrLQLrhs/uAxPRMtG02xRb5JjOLWjHlY9+YeQhaP4SIMswtglUAHF8/cNMUAsB4ofkmf3Zre4ghqakciUWBMr0XbnmBu/ZxnRUCl9KYTCEApMRS4IeqmEkgW1goSjEqP91ZLn7V3Tdl3kyEQ7cddwREAI77CG/XPzTxD/Xm6PTWHw7ZAGOtqSUA1J2HWHjt7tW9WZm67HOEQkH4Xb1gdsXSQF12NH0WbMzJV+y1TEz5XiBBsQ4Bv1+135D9tZfuar6/paHBsUgMAWHe3ZIexZkLf+3Kyqa/k1/OxsM40Q8Cza5pZt8T2vCp3srwd5m2tRIANjnGy1tqKMb0kj4wFO0ekzxWEmJFIIy4KrzgzsEqM1YWF82a8ya8dYRnvLXLQCEbBKwgN7SD8btSR6Z+KFPHH7fSmCWglQDgOgJ3/jcJWv33d1YHLGQlgdTEcYAI4iqRCIFZCIgAzIJPNzsEor8SsyYm6NoypjUEgMX394ImyWLKhlHjZhgbMLRGNs0zuIvYNDiUBT95TihyhNYYqw4SM4Af2wvfGpsdmnmSGo3TP+Md7kwF/o7Z+mGZhmE699Xj/r2vhTB0uAx9xKJyevcsLCo5F0gLAYCIEBNCzEESfO9o9GzWQ4Ib57mhPbg+iMkYSunEzfEb4YEQJto7ZGLHn04Mx0XdfR/tx2gopqKFAKDxQ04pgJUEEoOrDDJSK8xDyFESrBTMHYkQmIWACMAs+HSzQ4Ac5ce7/35vWFhLYJUIABobPtSvdg9iE7m6maGxzhXSBtkIk1CxEFJTU3wl3ssiT8pWFE7R8/5byBGHv9QELGJG9howaWFolWyoXmIcBr+xaf1pAaDbZKrNcRgNBMtLCwF4RB/rkO7H6oAmj1ZeErTzGFPB3yAqOWEuQBCSoHX7QlRD76M90YVCnAJzLSe1BACLBNYWyGASNHkwhWS0SMwGAJd4zkXL83StEPgiAiIAmghLIRALlxBV7guZlN4zRgBY2PFnE8WdhEppmNXRbucKmuAHgpmaNMIXVz4YUzr3+7gB2kwpZC9s9hzw4gPybtoHu5VeFTdeLCFoylEILCPaPMnQdfE+1gJIm/efk17pD2jinloCgL8fEvV17kVD7pGhvnM6Hm6SJPj3IXxRwBM3A/hibcDycC8ze3QJ1P73qGE/uL8/d3sNAQBLYh78OPxT7zZqCWhM74/WDYiEtyRVdlOXCYGTIyACoBmxFAL4sjm5LAnBS/4goNJ7hggAWjipWkR3e7n2guelE1lNtHwSNnM2wpZTA/Fp4+9OMpTe9bvdsa/EMSRBSyToriRszpSDTYKJH9+2F0z4mJZ9sN2Y1hzfiYWCtpCOh+UDszv98FJLALCmxOJPzA/cLLUSD5MidoBYgRrSx9pWO35o1OCUhJgPgkFzUkMAYklq2nuVxr77d0Mmo8sEMjzX7VU7DrrumCIgAnBMB/YIuoU522/SLRo0zc0RAILTXjVwLDC5+ETA5wLVWrvPJkwwXBJcGUTzt0h0gaD9e5N0ehYkAbKQBFP+efs0waH3fUefs55+Z4NG242FjkgXiyZ7NGKwWkpqCcAvd+27t3spaZAxYLLUpot31RyJe/DCRsqcWFLwp/vxhqR5d5B/V4kAkAXjj7smloAYlZoshqE+MYZYELwQV0B8hUQITEZABGAydLrRIXCmjFbGpuWLmJQAiwSAdD40p3OO3PiuPke6RiMcez8bKpplkjv0qYClNvvf4+bLwo+WFoPWcBN8MPQLczVm5yF5qJn9rPtxyLoQqyJiDfD9aunP0LW1BAAfuo/mJ9jOk6yatoAV88C7VqbWTxh7X5x7VJL0Vhp/7xgBiBkPjD1EGEIxV8hw8fEvuH9w70iEwGQERAAmQ6cbHQK5/HQKAFEtr1biIhzvS5XqYtQ7sQEEbU098IdIbdLQvGAKj5p0qR/4uqko5wWTfc7ny2b/8+7CUsAk6YfEKSQZIlcx6A4CxrVLSi0BgJx9s3txq/8/3Yo7xtcyICf+ZwodgjCQZkcQIJoyFhbIGP9y9R3I/EjHVvPoKQTgCr2rKmVS4H4grZTYmCWEtD8fnzGFpC7RDj3jGCEgAnCMBvMIu4JvN+azt/oohwgAmjSBaJT8RTDPx1PRKNzDgjhF2FjZYNcQIswJZIvCQs6m77+/XMQ997GxENGeZKwQTIwWx+xMVsCSUksAMPmTb5+E+4i1aBViBnzBpCf1lQ1zzyHyHksJsQOkoE6VVgLA/Icw+nfiEoMALeV+IXPCZ5bQx9ogx6k46L5jjoAIwDEf4I26x+ZFpTMvRGYTtFUrOQJA/j0n+nlXAhoctfdjjvpQTnzp/SyqNWlppefkfidLgQDGnJBn7zfnIRJDICWLfZIxEzhBgZick2CGry29W9u/WgIQTdYlN8fQ+18b0vmeZ2Y3y1yMqwNrkA9Ere1TvK6FAJDCSbZDLiqf2BKCVWuDEcfaCwmEDCYhvsKfCTG1r7rvgBEQATjgwV+w6+Q6+zxz8r19zfOaV0UC8Om+Ul3Ov89iT+42B9skYZGlilxt6l66LxdoVtPemmvwCf/OwIVUScStkYT+Eu/gq8PxfRIvkILnSocIRQIwlDZX0/aha2oJABHqvqjS1A0r1sKnDoCP2KedVPej4E7M+8e1Q3lm5iYmdLRxLEqRmM6JAShheQ8zwzUzVyCSnvSStfILcx+q+w8bARGAwx7/pXq/hgWAwLwxMy6V0ahXTwBiEjZPtOqc2X2or2yulMb1wjPmRG3X4IrPmYIwZ3EXkzfOmQFJUhZE+m+yB24w8vDoAkB7pmTxklJLANCKyVRIQlbAfSc0JJq+qfb34+E5uSJGBB1CFGoq7i1FADiYCbcHlQ6TkKkBMaFuxRyJRIg4FQ49kgiByQiIAEyGTjc6BHIxABzx2lKbv1QJMAc45m0ioX2deSrjkX6H5lwjaKkxn5oUsCUit0vvj+lnWAt8LYF4uNKYRYF3RXcBBwf5QLxSe2p+ryUAsbjO2KmFY+/lZEKC+JKQEeEDKPk72r8nOriOCP6rPRiKtnlS0eIC4P1YFND0mcNYpyAtvvY/gaAEY2LlmSqRCK2RDTG1bbpvpwiIAOx04E6wZq+RBVCyACQIWHgfHvAgUI4NoXbBjQFrnM8eC+CsAXnuvHeyJzBdE0NBu1IdfTIqsFaMZTvQbh8YhsuAqHRqDSwltQQgFjzCDE8KXYtgJYFEeoJHnj0bdhL6xzj76oqtRahiHYgWAgC2aPw+JY9aBfTXt5vKgBz9O1ViFgDVAQmIlAiByQiIAEyGTjc6BNaoA1BLAGhGNH3zNxZ1cqVrNr9Yy5/ULczKW0gsd3vbviY/OfP0IQl+ZMjOmGBqxuzvBZJRG+RIBUFfzIm4iliAppYA4J9+gGsI/nfITUtAHGWAozsnZlYQfBcPa8J1glWgRiAQ9NGXmW4hABAUrF1RIk78TnVBqgxOkRhUuZWVakpbdc9OEBAB2MlA7aCZa1QCrE3lIuCQICliEbzU5p5jUvaFeIYq7a0xDLGCYCqYw0bhNUayFcaOw6VtuVLALb7i2Ba0Tqw7XmoJADX76YsXotjHTgGM+MYSzZj0iZnwFRBJEYzlhVuOy71jHyjo370EASBbBRLiI/dxNeEKaD3KN1cJsGY+rDFf9cxjhIAIwDEazCPuCkFOvuhMqxl2SgyA7zKLJJkBvmAOv9fkS2Nax9fszcilc+Ej3Gx4BGWRosjGR9AWJviSYD0hGDBVecPEj1aLDz1plmB7mdKD+t8JIry5u5Z+sSHGssG5x3FcsE8bzFlCagkAWPJuX/73ad1hSFg4aoQNlGJCvvhNrkb/+TPloCkRHU/4y72TQ5xIMfUHFnHdWPZEqRSwfw8FjCAnPlCVehlUjawZj/Ss3ImFPLPWxVWDt645QAREAA5w0Ffq8tPDASpjB6rkmjCXAPBMtCI2Xp9+RoAWwXOlsqmcJucj7LECYIJmEysJgV9kJPjDelrObI8nKUIi/Kl3dw315cfaE1MyufYXu0C1+xc6QebDK0Jxolwdg1oCwOtIVfPFf3DH4Kao2ZwhkFT988LGCc5eIArETPgxr7F6sIFSJ4FnEjjqS06PVVBsIQC0M3esMXOdIL5aiacBMichPhIhMAsBEYBZ8Olmh0A0pbZGoC9BAGgOAVls5n5uY3q9UuE0NmoKoK15fy4VAilENJZWeMk+dY//TcKRv6Qp+pz+sclC24bSDik0QzodLpZaiTEN3MdGTOGYXEwENfuxHHj/P0QqulR4TgsBwK+O28JbZfC3478eIgGMG1UdCfTzQXS0zx+v67GA3FFwJwlYYTEZOigKokjZZggbpYYhSFgnkmC54UjhXA2KVgLAMyM55m+cNYCroUZijEuuFkLNc3SNEDgZAiIAmhBLIRAr6hHshQ+/duNaigDQHzRANiov5KWTHkhk/ZDk8smxIBDRzj82C8yubGyk1xGox0LuNyo2D7R3Kv21yLu7TfiimRue37kDbtryoD4XHTKTMgjS7WyIFAvCB01BHNLrMPnHAjqf6rGCxEVpIQDci0UCTfvU7kGQEPpF0SYwxbfPXMHigvsCk7cXiBippvHMhnRNLt6AoEPiOjDnMweJHWCOUikRSw8uCszwWD4giDG+gs35pP6dEDnmDzKFAEAqMf17CxHHLRO/MDYfU/9iSuVWWSqN006X7w0BEYC9jdiJ217mEgV1fPGXW3b+Z85ar5ElCQDvi2e88zcWYSLEx+oT3Ko/CdBvWDXt5xo2Cvrsj/utvZca9uS4R0GzxTffKpAJNj/83C3CJgspiKb29IxWAsB9ECWIhz/NrrZNZDCAQdqAh+5Dg2/J3ICoMVYQEeYuRGTIrM7YpFTTKQSANmORwKri5xUuF543VjI7F+MA+cyRs1pMdZ0Q+CICIgCaCEsi8Bgzw/edBDMrJvQaWZoAkEOOWT1qkxTbQQMcW3TRRNEeW/LWSdkj4JBDfqYI2joEym8QBAeygdekMubeSdodFfjYGH2A41D70NTxN48VUZpCAHgfLhEIztAxu7FNWFqoafCQTKGmXPvBjcJKtL8kWEA4qc+nTGJ58FUY/TOWIAA8L0fyqI7IGA1JjIUYOwyq1G/9LgROhoAIgCbEkghQfMfnX6NpswnVVARcmgDQL8qyvilEovN3KuaxsJYEIoA2TA12/Nj4hQk2Q9OnMA9mezYRTNn8/7kSi+ew+d1z7kP7SHoCITGVE+tAP1LKIJovBzk9sxAjkZoxlQCk+zF7o9FDrsAU0z9twUyP2R7XBYf6gEWt+8hDhKuADA4sPVTjw13DeEFqiOUgPoJ/OVIFRhw1TO0ECAXBgaQtcgR1igOZagGgjay3ZIhwVHESsj5wQwwdPx1LABPLEd1bC0wRPeIQERABOMRRX7fPsWRprNy27tv3+3S+RTRTf8ARZvypFoX9IqGWe7LkaxwQs4BLAMuQRAjMRkAEYDaEekBAIAbSkcvNiXuScQRi5T/8wwTQSQ4XgaeEugktdRQOFzX1vBoBEYBqqHRhJQJU5UOT9Qe4lA6xqXz0sb6MrAFMwUmIU5gSTHisQTqgzlFAiUOEiGVBcFmQxUBGgEQILIKACMAiMOohAYFY/AQrAKezTQ1mO+4A36jPS0/9xOxP0NxYoOJxx+TQ+xdrB0w9TfHQcVT/RxAQAdD0WAsBguN8fjl15p+w1st2/FzKxVIUx597QMGboYj0HXdVTa9EgEBJUlZTfQlSM6khQO0AiRBYDAERgMWg1IMCApfoI6eTCfOTnZZLtbyawieHAiYmXcz8kIAkRH2TTdFyat6h4HUI/aS0MXPAp6+mEyIPof/q44YIiABsCPYBvoq8eFLukpBn7g+bOSRIOHDmxn1qG6lpBPjdrEvpYsFPQkU6Ug8V+X9IM+PkfY0nIFJAiXkjEQKLIyACsDikeqBDgPlFSVW/6bccbHOcwMT6MXacLylenGNAQSHJYSKA1o/rLBWD4kwJ6hpMqYdwmAiq100IiAA0waWLJyBw5t6kmVIBKcFKMZWhw28mvGIXt4wRAArO4Pcn9U9ymAhwGiHFhtLxyVRCxBVE5T+JEFgFARGAVWDVQwMC+LipqEYFOoSKb2g7NUftHhcwKeBCTX+q01ETHwxI8yLYj6OTMf9LDhOB0/aHR12h7z7ZH5yYWHta4GGipl7PRkAEYDaEeoAQEAJCQAgIgf0hIAKwvzFTi4WAEBACQkAIzEZABGA2hHqAEBACQkAICIH9ISACsL8xU4uFgBAQAkJACMxGQARgNoR6gBAQAkJACAiB/SEgArC/MVOLhYAQEAJCQAjMRkAEYDaEeoAQEAJCQAgIgf0hIAKwvzFTi4WAEBACQkAIzEZABGA2hHqAEBACQkAICIH9ISACsL8xU4uFgBAQAkJACMxGQARgNoR6gBAQAkJACAiB/SEgArC/MVOLhYAQEAJCQAjMRkAEYDaEeoAQEAJCQAgIgf0hIAKwvzFTi4WAEBACQkAIzEZABGA2hHqAEBACQkAICIH9ISACsL8xU4uFgBAQAkJACMxGQARgNoR6gBAQAkJACAiB/SEgArC/MVOLhYAQEAJCQAjMRuD/Ae+CuTWsHTdQAAAAAElFTkSuQmCC"/></switch></g></g></g><g data-cell-id="V1Wl26Vbpgnno5Lb-wtg-48"><g><path d="M 666.37 344.13 L 685.47 344.53 L 703.63 344.14" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 661.12 344.02 L 668.19 340.67 L 666.37 344.13 L 668.04 347.67 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 708.88 344.02 L 701.96 347.67 L 703.63 344.14 L 701.81 340.68 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g data-cell-id="YJRAzF6yD4Hh-bAvO1PB-16"><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 345px; margin-left: 684px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 9px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">JDBC</div></div></div></foreignObject><image x="672" y="340" width="24" height="13.25" xlink:href="data:image/png;base64,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"/></switch></g></g></g></g><g data-cell-id="iy0HhJzZLXsiPmpU2ukH-6"><g><path d="M 595 364 L 595 410.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 595 415.88 L 591.5 408.88 L 595 410.63 L 598.5 408.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="hBEam5F8n4ZBPeoiEcWH-1"><g><rect x="530" y="324" width="130" height="40" rx="6" ry="6" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 128px; height: 1px; padding-top: 344px; margin-left: 531px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Metadata Service</div></div></div></foreignObject><image x="531" y="337.5" width="128" height="17" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="YJRAzF6yD4Hh-bAvO1PB-15"><g><path d="M 308 248 L 329.06 248.04 C 329.07 244.14 335.07 244.15 335.06 248.05 L 335.06 248.05 L 340.06 248.06 L 340.06 294.06 L 420.06 294.06 L 420.01 317.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" stroke-dasharray="1 1" pointer-events="stroke"/><path d="M 420 322.88 L 416.52 315.88 L 420.01 317.63 L 423.52 315.89 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 294px; margin-left: 407px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 9px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">Spring AMQP</div></div></div></foreignObject><image x="379.5" y="289" width="55" height="13.25" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAANwAAAA1CAYAAAAqEYXLAAAAAXNSR0IArs4c6QAAEzZJREFUeF7tnQOQLEkQhvOdbZtxtv3Otm3btm3btm3btm3jXXx1kR05tdVdPdM78/rmVUZc3O1ud3VVVv2JP7P7+vTr16+fJEkaSBroiAb6JMB1RM/pIUkDTgMJcOkgJA10UAMJcB1UdnpU0kACXDoDSQMd1MAAA7jNNttMTj/9dKfaLbfcUk466aQOqjk9KmngPw3kAu7333+XW265xf3zwgsvyPvvvy8//PCD/PHHHzL00EPLyCOPLJNMMonMMcccstxyy8kMM8xQa50OyID7/vvvZcwxx5Rff/0126Nnn31Wpp9++tJ79tNPP8mwww7bcP3OO+8sRxxxROkx7IXHHHOM7Ljjjg33Mr8hhhii1Hi//PKL3HnnnXLXXXfJ448/Ll988YV8+eWX8tdff8lwww0nE044oVvfEkssIYsttljpcUPrzJvQwAMPLCOMMIKMNdZYMttsszkc8Lw+ffrkriEIuPPOO0923313+eyzz0otnosWXnhhOeecc2ScccYpfU8nLxyQAXfqqafKFlts0aDurbfeWk444YTSWxA6iBy0Dz/8UAYaaKDS4+iFM844owB6K2UA99tvvwnrOeywwxzIyshoo43mwL399tvLoIMOWnhLM4ALDTTNNNPIhRdeKNNNN13wOT0Ax6SOO+64houxjlNNNZXzaoMMMohgMV9//XV58803e1z32GOPyXjjjVdGDx295rvvvhOUiQwzzDDOMg0oMtNMM8kzzzzTsNyRRhpJPvnkExl88MFLqSHvIN5xxx3O2DYjr776qkw55ZQ9bokB7qOPPpJlllmmB1AZiHWMOuqozrsARCI0X/B41113nYw//vi50/XXOcUUUwi6CgnzxSmhRyt46bvvvlvmnHPOHrc1AO6KK66QVVddNbtogQUWkEMPPVRmnXXW4APfeecdOeCAA+T888/P/j7PPPPIAw880Iz+07Vt1MBzzz2XhfsYGf5577333BMvv/xyWWWVVUo93R7E0Ucf3R1qeibWWmstZ9GbkT322MOdKzwjRpxQECkC3Ntvvy2crU8//TR7FMDZdtttZfHFF5fJJ5+8YQqvvfaa3HTTTXLsscc2AAKv/NBDD7mQMyQ+4K699loXKhbJBx984DgBwuS///7bXYpXfeutt3qE4Q2As25+0UUXlZtvvlmIU2Oy9957y0EHHZRdduutt7q4OUn/1wChoxJEgIODwMFA2OPbbrut1CTtQZx00kllxBFHlCeeeMLl81h5ooYyAkg57HACeN5vvvlG3n333ULA4a3wFtZL77TTTu7MxTw0uR7h5GmnnZZNj7CPuYfyxVYApwNfeeWVDQbs4IMPFoyLlQxwLBxro4KXwqKUERJVNkEtJ/nCySefXObWdE0bNUC+g0X/9ttv3VMIpwi75pprLvczHoaDXybvtgeRlGHjjTcWDC1ChLPOOuuUWgnnar755nPX7rXXXi7v15Asz8Ptueeecsghh2Tj899wDM0IBM9RRx2V3UJkpvO341QBHOMsssgijsxBZp55ZnnyySfDgHvppZcE5KtgtQgdysqDDz7oGKJpp522Abh6P9b14osvdj8CRkCJ9bngggvkkksuEUKGr776ylnOqaee2oW2G2ywQa6HtSTImWeeKRtttJG8+OKLzqKwyM8//1z09zwzRppss802cuKJJ7r5YQ033XRTFzJdf/317lAwNuEMVnHiiSd2bBThzCijjBJVEaE6a3/66afdGrmH3GCTTTaRFVZYwa3x3HPPdetFVl55ZeGeqoJe11xzTTcMoSQ6gTSYYIIJhDAIwUtwoGNiDyIgvv3227PzsuCCCzq2sIyg1zPOOMNdSr6PHjH2SAhwMOMAHN4AIV/k2UVMYGgehHoYGhhNBMb1448/7hHyVQUc0QRRBcK+wupbUinzcMSbeCkVDi0I7S3BIp511lnZJnO4llpqqR7JvH0eIQchT+hQW3IHtm2hhRaSWWaZRX7++edsiGYAh8WE+UKOPvpoZxBWWmklF1bnCWQSBy1EAHAPc1l++eUzixcaB4t41VVXuUNImISst956DoBVhRz83nvvdcNgkNAHYj0GxgPyK3aA7UHES5LDcV44NxwoADz22GMXTpnDN8YYYziPO+644zrvysHXPQsBjr3FsKmQk+YxgDF94RTmnXfe7DI1rPa+qoAjb1x66aWzITGwNnLMAPfnn3+6g41FQZZddlm55pprWqJ8QwvffPPNszh6l112cdaN8AKPNv/887sN4NmwO2p9GWf22WeXhx9+uMc8LEAOP/xwQZks1kozgLN56IEHHigk3Xgl5gcosOrMj7nwNxXyXjxXSGDUbrzx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"/></switch></g></g></g><g data-cell-id="AQz-Vj6r_5Wor37pQVs6-1"><g><rect x="178" y="228" width="130" height="40" rx="6" ry="6" fill="#e6e6e6" stroke="#000000" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 128px; height: 1px; padding-top: 248px; margin-left: 179px;"><div data-drawio-colors="color: #000000; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Broker Service<br />(RabbitMQ)</div></div></div></foreignObject><image x="179" y="234" width="128" height="32" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAgAAAACACAYAAAB9V9ELAAAAAXNSR0IArs4c6QAAIABJREFUeF7tnQX4BUtZxj9JCekSFKQ7BCSk4dLdjTR6kQZBpLsUpKSbS3e3tCIpiDSIIN1Ih/u7zvh8fnd2d+ac3f/Zc877Pc997r3/Mzs7887uzvvl/I5JhIAQEAJCQAgIgb1D4Hf2bsaasBAQAkJACAgBIWAiAHoIhIAQEAJCQAjsIQIiAHu46JqyEBACQkAICAERAD0DQkAICAEhIAT2EAERgD1cdE1ZCAgBISAEhIAIgJ4BISAEhIAQEAJ7iIAIwB4uuqYsBISAEBACQkAEQM+AEBACQkAICIE9REAEYA8Xfcem/CAz+xs3p9eZ2ZV2bI6azn4g8E9mdn431TuZ2WP2Y+qa5SYQEAHYBOq655QIiABMieYR+zqymZ3ezM5iZic0s98zs2Oa2c/N7L/N7Dtm9nkz+4yZ/XDeoex87yIAO7/Ey5qgCMCy1sOPBuZ/h4bh/TZ9kH9sZt80s0+Z2cfNDI34Iw39bFtTEYDpV4wN/rpmdm0zu6SZHb3iFr8xsw+Z2WvM7MnpGay4TE0cAiIAehwOFAERgAOFu+lmrQRgqPPPmtl9zeyF3b8hCrskIgDTrubNzAxMT75Gtz/rSMNDzezBZvbrNfrZt0tFAPZtxTc8XxGADS/AwO2nJAD5Nq8wsxua2U+XO+3mkYkANENWvABT/xPN7NYD3f3KzLAwscEfI7kDjjTQHuvT1cyM6yTjCBy7I19Hcc14T3G1SITALAiIAMwC6ySdRgLAh+B5Az2zlnxATpL8tfy7JC9Npt1JBrmATkQAplkENPZ7hK4w67/SzF5mZh8wsy8Gjf5o3TN5OjO7WPfbn4UAttzVk8zsL6YZonoRAkJgSgREAKZEc9q+IgEg2OpEDbc4j5ndxcyuX7iGKHm0s10QEYD1V/EcZvZhM8MKkOVzZnYtM/tYQ/fEDTwtEdF8GS6nPzUzzNsSISAEFoSACMCCFiMMZV0CkLu7Wxe1/YjQ9y5ZAUQA1n+G47OGmf+cZvaFFbq+jJm90ez/nTTK/19+hb50iRAQAjMiIAIwI7hrdj0VAWCNyQY4qxsPWQInXXN8S7lcBGD9lfikmZ3ZdfMUM7vNGt0+uyMPN3HX40o4pZl9dY0+dakQEAITIyACMDGgE3Y3FQFgSI9K7oA8PMyypHb9sme8uAhI58ryqhTMxf8fP/mKr2xmpzaz3zUz/3sfBOSPX8HMLmVm50vuDPLKiRLHvQEpeb+Zvb3zJb+hIfhpHQJAupoPemOjwoyNhWRIjpeKDV2285Gfy8xObGYn6DD+kZl9O+XFv8XMXtsFXZKBUSsf7HDHdZPljzvcP5r+53JmdvvOdfMn6V4E3/nfa+9Rase4iR/JwuYPCVhVmAPFmT7RxZv8W/r3pxuCAZeE7927lNrrOSAgS55Mt2DEWmJZyfKi0Pc6WQBH7dwsPCNYWi6YCD7vFwGb30opmm9KmUA/aRm0a8t7S/+khv5Beu6JA6H//P5yjzc3vL8rDkWXTYGACMAUKM7Tx5QE4K+6qO2Hh2FCAH7RM/RDzIwNLAv/jWn3ZN2/35c2fn/pEAHgA3G7RBpqYxi+klLR2ITG0hZXJQD36nzeDwzz//OUw963opCdO5sZeB63YtkhFM9Nm2GN9vueDvcLuX75b/BmE3pY4X5TEQCIoI8+P7TbQP6hYn5TN1kivmx0ngwzZwgARKBFztDF40CCvMRYnFUJwFXM7JFmxj3G5HvpXXxqxbuV+4J08v24xFjn6fcvpWf+sMr2arYhBEQANgR8xW2nJADkY9/T3RMtFa21T9h42Iyy8N8XSR/CUpndPgLAJvnypDFUTPkITV5gZjcdICpcsAoBwDyNmdoLGutDBgaJNoVGf4EVJoJ2BIEaC6iDaEG+svDfVNdjYyil201FAP6rIz6/7+4LNuB+kLJUfLFgfC1VQcx4UFPjAY3g3Dtcg9ZMrQWfIrkKAbhfqvHROJzDiSk1H8bqNJDdQWCnJ4i19yID5LZmBhGWLBABEYAFLkoa0pQEALO6Z+9jJvvzmtm/OGio8MaL7CO5s+mefHD6J9/bCx8MiIOvbc7vaAfP70jBu8zs6ynyHMsCZkU25pi+CAm4wcAytRKAS6cMCEymWcCauut9cqyUBkc5XC//ambP6cyi/5zcGMfpTKxnSlhcNQTCfT+Z74mu7xMIxhXdj7hZ/rJzjeBqyAIhwHKDmRzNLLsI1nmSqQ/h149N6cJpXuv0W3vt0vHFGoJ1KAuujbPXTi614xrvOnhsodJnKwGAtPL8e/lucsmR1YFrDdcbRBHXFu47L49LbqW+qUAQnhF+5NnjmX99epexHkEeeV5uYWanCO2fkJ7hRrjU/CAQEAE4CJRXu8dUBIBNImqQbCxsNn3CB4MPSBbMnZCAG6dccMzgpBHmGAI+4NSF94KWhHbihUIzdx0oRMQHCu2T8XkhHY1c9JK0EAD8r+9OH8XcF5oQWs6QqwFNxgfF0favk9m1T7vBioL1wxOaf0xEp+9eEDPMuVm4B/n5CB9SYjkgUAiuFfrpi+Pogav4Z/B9SfiFTABcN6zHmBum5V6ltkvHl82N58YLRC+a9PtwYOOHAHjhvSTmw0sLAeAdhXh6IvviRFQw80eBMEK8icPxgmLAcxmF+g6QS97tLHwHeD45+6EkuHAen4iA/x1y/44+cPT3zSEgArA57MfuPAUBIECNjdqXda05LY+8cG+uRlPnQ4DrgA8XmsWQ4F7Aj88mlYWPE1rImPAR4cPGGLJwroGPUvd91BIAotAJMvRYQIKuPhKcdu5Efvw9cafkjXloPgRNYQXxH+lrJmJQug7CwHiycMAOfl3qOfzdGHBr/o5FBjdPFEzgz0zuH8YztWwDvnwnKYJ0Kjd5TPpR++7DBncB7bP8eyrWFdu3EAA21Iu7DtjEsW4NVV3k3eJcEMhLlhzfE8cSySgxLHxP+AaMSbyWLCT/Po9dr98PCAERgAMCeoXbtBKAXAkQcxwv6jVSIRdf3IUPDJHCPxgZz9lS6mBshh/bBwf2dYOWT1BSFqoYolFACmokZiFwTQ6Ii9fXEAC0n/eGjy4bM/MZK4v8dDO7ubspWhFR7rV+zZhpgOnUm/n9fMg+gCB4YdxooHMLlgruxTr1yZeTJgd2BCeyka1rHdgWfGOlRAgy71mNYCnwAXp9BLKWAHA6YyRjJYtCaWw3SoGp+TeeY9bek3qIDjUgfNwJ3xNcRTXyh+l6HzcAGfZuxZp+1GZmBEQAZgZ4je6nPAuANC/6Y7Psi/z3Qy0RAPzdPoVpaGq4DzBRZhmLOYh98eEhcI7AsCxowGjCUcYIANkOpCVd1F3IXPj/MSLEtZhTiXPIQnBcDCAcwoJNwp/GSOwEJI0gsCglAtDy4V3jcTv8UlwwZF7gEqgR/M0QAczjpG6i6bXINuFbeifY1MfSPOP6Q5j+qCOVkKkotQTg/h0BvY+7GILhtfqhNSBd9a1pw2fT5x++DX4eMWARMgAxbCF7lJAmDibLWLxBy3OjthMhIAIwEZAzdDMFAYDdY3rng4EZvVZKHzs2Wm/G7OsLMyOEw7P/VfLKGTfH0WbBxFlKQxoiADzfBBF61wP+SzRq3BpjQgCjD3zkA0jAIuSkVhgDUeS+8BIWACwBUSIBwHICCYrxFbX3XrUd+LDWmJRbvhFsargx8AP3+Yn9mLYNX4ijD/6rcQVFy0HfcwwutQSAXHusV1mIrSFIdyqBzGEpXKd/zn9gXFnQ/rECSBaEQMvLvaBh78VQpiAAHij86uT+Pqsi9adEAGDzr65AnjQ5fO1eKEzSWgs+ajlo65jyowwRgL9Nefv5GjZ9XAm1JW4pvPP37ob4QckLb5X4waYGAamZUSIBwHKAj3xTgqaKBQLCAm5o7DUC8cRcjJY6lC+/bfjGegw16wMROo0DDXcSMRUlqSUA+OG9dewOXXEosgqmEqwCWAqy3CqlArb0zzuPdSgLBYnISNDJkC0oztxWBGBmgNfoPhIAfNVjgWD4+3nJ8omApK3FNUaL4aM+pKGVCEBt8RO07ReGeRMUWBM85C8r5eozN6LTvfQRgLi5kIbHqXXMv1YebWZ3dI0xkw4dl9vXL64LXz+BaGx8sVEiASAy/zq1g525HW4QNDiIAIf7QPT8JlS6Pe4mNiei/EuybfgSSEoWhn+nMI33vUv45TlFMQvvMBYkUjlLUkMASDWNrqtacl7ziFC7g3fFC+mGfjOv6YdnI1bUJHZhKA22pl+1mRABEYAJwZy4q9YgwNLt8TWTyxsr17EZ8wHv+3CVCAB91ZjN2SAJfPNCFHwr8ycvPQYdkWNM0RovJQKAhoULwQcxEeVO1HSLH5N+5iiI05eJEQkAOPr884kfsbW649uB3xl3AXUKcBewOZXklmZGsF+UbcQ3ZktwhHKsspnnGUtwQ4xLp3Pm9jUEABLyHwHIKdPsCADMqaZrPSCFi2sDFae+r/rrQUAEYLmPxhQEIM8OLYXAH5/GNBTNXiIAaAZ9motHMZ4+iB+buIBWYUMheM8LFg0iz71EAkC6FmSldM+hj3VpfDEtr3UOfe0JmvNBibldJABoyNRc2AY5ZirYRP2H6CZB80X7i+WQtxFfCJkvk0wuPxtbFL6tbNRExGfpi/3Iv9cQAGIQohULMo+LbwqJKcBT9Jn74BwQioZJFoKACMBCFqIwjCkJAN2z4bwz3AdtJJrraVIiACXzewm9mAKIGbjWd+z7I8gJ37mXUvGVSACGVrS1wl0MRJzqaenzHUcCQAwDeG6TcKgQ8/DVCxk/R1LjQ/eyjfjiG8cS5ms7cChW1Jpxk5BWmeUbiRgNWcJWJQB9KbKrPDeQbGo/zCFTuirmGN/e9SkCsNwln5oAMFNyl31BDqrrlVK+1iEABAzFk+RWcQFQEAcN0UvJDdFHAKiQh/aM/51gtixYCEhRHEsBpD1Bk5ivs1B8BXPrXLILBABssAbgXsLfnaVUPndb8SUY1lerxOqFud8LwaPEoWQZKzdNuxoCUHIBYC3DwjeF4GaL9TqIncH1IdkxBEQAlrugcxCAWHQFE6XfHDMa6xAAgtY45tQLKXAtqXNcW6pDzsYSC/eUCAD56QQ6YvFAE+Pj5QsixWNY+54Cihl5DZz6Bv643qmfnl0hAOCCX5zYkywQMl8Zkr9vK74cD0x6aRbM7/6QKGJP2ET9AUs8N768dunZqSEApSC9PkveKs8nFT9joC3lf+OJiKv0rWsWhoAIwMIWxA1nDgJAFoE/9IZzwX2t7ykIAB+6WOOcErP+dMEa1DmZj1r4WSAQPpc+/z0SAD68aOlDhU24ti8wzY8tBjSSHlV7pHHNHGObTRMA5taardE3z1IwKM+aP4t+W/GFiGLSx92RhfiaXNwHjdnX1ycV0h8E1IdZDQHg2pimt8rphEPPZzwdEksGhXwkO4aACMByF3QOAsApXhzokwVfptdSpiAAmPspBOT9/hwqQ3GYFkHj8KlzfZHzY5UAuScaGeZ7H3jHRsSphzGo0I8xHorEbyV/b8u8htoeNAGgSh3FliBt/EOqHyRrisJDuF+IYciC5YaNc1fwje8SpzZyYBPCs+4L80BkH1bxkNQSAIJjMftnoeqeP0Ni7Fak6PkYBt5Xv+axlv8mjocem4N+nwABEYAJQJypizkIADm4p3Xj7TNpr+MCoHtyhikEkuWNXZTy5Rtwgjyg5XjrRN/hKzUEgFsTjU0MhD8SlWhqqtFRpKQkVDPEnUAAZJY5D+Y5aAJQOnNhKm2P+BLcMFlK5Wq3GV8q5VExL0smqHxT/9Mdi0tRJKwDNedg1BKAeLgQJnusN2Tc1AjWC39K5Q27swoOcxfGgke8ixyiVVNGvOb+arMQBEQAFrIQhWFMTQBIQYpHABO4RABTlHUJQCwDSuQzEfw15WEZC8fzUrEwC7n7pJGVrq8lAPTFhhSPFR47rzweVcsYMOfWfmy5L7ijYaG58Q8bREkOmgBAtDD3+qpvFIGh4M9YjfuhN6d0VG1fRsO24ktMCdjljRSLEjhiVfFVL0l7I/2tRmoJwBkLpb1JT4z1N0r3ZG1jyiCVCgmOzUIgIPFBPm6mxmXm70cWD248nneyeVAKpji6ugZHtalEQASgEqgNNJuSALB5EhAXzf19gUnrEgAKwpDz7X2kRE5T3GesEA8aOmlyvmYBHxBfm9wvRwsB4Lp4Oh9/w3yKGbUkHIBEzQQvLel5uD98mVbOBWBupY/hQRMA5kSlQ+oNeMGXTXbIKqe3sfljQvb57xyABI6l9LJtxhe/OKb/LJjlOa+CMwKyEMzqyezQp6SWANBHLEiEO4/3ORbK8vfje8+GfIj7Y19NilijASsA/cciRKX5QISYC9+dLKu4AYew0m8TICACMAGIM3UxBQGgIAuV7DDp+c2YIT+j00Rv0TP2dQkA3cZSvPwNbY8Np097ZtMgN9xHVNMWraWvhG8rAcAPTZDimd3cMfOzEfWZaSn8EivyYT3BLdHnPsDHCu6Ya/175n3FEf5NEADGCTn0LhvGhdWGksUQJjTGoeOPmR8bP0F9bHgx2n/sIKltxTeeewExhATkVFusAqRC4mOvkRYCQPEhztzwWjoEiyyc0vkLkHLev1iJEGId620wVlyFEF//3aDWATEjMcjXz41vBxkS/DsLhJL3zQeA1uChNjMjIAIwM8BrdB8JABvh8yr6Y4NDi8bkjqZZWmM0Oz5UfbnwUxAA7suHxQcrMXziENCIKJJCZD/jJbeZwjH4ImNWAoTBH8gTIWglAFzPZs+m5gMV0YTQ3tBWozBGMKNIihc+bPhOMW/iVyXYEF8phIVUMW/F4Dq0Lz64fVaQTRAAxkVQGBplnF+eK24BCBjuD54ZAvrAjk0F8zHPi/cpe4wgEZDQoQI424yvj6tB+2b9s/Bs8EzXSgsBoM8YC8DfsCwRm8B68n7xPqG5XzPEv9B2rNQ06xYPLoIIEqDLPxyqBbkhRobvDc82cSW+BDfjwR3gsyJq8VC7mREQAZgZ4DW6n/o0wDwUXlw+SkNayRQEgPsRVc6BNsQftAofGlIWx045W4UAMJaShYITCO/XM1A2SbCLmnLtvCjUggtkKMJ+UwSAOaDpEQ/BIUxTCCSBEw/xA4+5fbjftuL7wI7ccLpjSQh8JQC2VloJAP2SXRArLNbcD3LCWpcIr7+eNk8LWQM1/dMGjZ9vTZ97rbYftZsJARGAmYCdoNupCQDmPDSGeMBOaahTEQD6JtL70PSR5FTAGsE6QOoUWvmYrEoA6JfgPE9O+BhSQ6Cv6hnnC2CRoMCNzyYYGiNaGJsg/uIhMzp9bJIA5DlgvQB7cPGpYmPrkH/HnQLpY11qIt99v9uIL5pvKZUUixDBdGMbrJ//KgSA69HuKbzkM3z61ov1IUahJmAw94EFAaLhYwfGngesELwrnxlrqN83h4AIwOawH7vzqgQAnzRmWl50yq+S6keK0sfHbuh+n5IA5G7RMNlUMPWTfw8ZIFgI1wbFZ4iMx0yIxoRvs1bWIQCMAdO2L1nLpoWLAPz6BNM3c8G9wceRftBg0XQ5MImIalIOcYGAfV+cQOx/CQQgj4k5YrqlkiJR5wR0HS9ZCjD/Y8kg/ex7KSKdZw1XCFHv60Z7bxu+HzKzc4fFXOUgp1UJALeGrGFx4B+sVLhkeCZ5v77VlS5mjDyP+OdX9cXzrNM/rjLcWzz3ubgTRPdTybWHksF/SxaOgAjAwhdIwxMCQkAICAEhMAcCIgBzoKo+hYAQEAJCQAgsHAERgIUvkIYnBISAEBACQmAOBEQA5kBVfQoBISAEhIAQWDgCIgALXyANTwgIASEgBITAHAiIAMyBqvoUAkJACAgBIbBwBEQAFr5AGp4QEAJCQAgIgTkQEAGYA1X1KQSEgBAQAkJg4QiIACx8gTQ8ISAEhIAQEAJzICACMAeq6lMICAEhIASEwMIREAFY+AJpeEJACAgBISAE5kBABGAOVNWnEBACQkAICIGFIyACsPAF0vCEgBAQAkJACMyBgAjAHKiqTyEgBISAEBACC0dABGDhC6ThCQEhIASEgBCYAwERgDlQVZ9CQAgIASEgBBaOgAjAwhdIwxMCQkAICAEhMAcCIgBzoKo+hYAQEAJCQAgsHAERgIUvkIYnBISAEBACQmAOBEQA5kBVfQoBISAEhIAQWDgCIgALXyANTwgIASEgBITAHAiIAMyB6n70eXQze5uZXShN9zdmdlUze+1+TL93lg8ys79xv77OzK40Eybvcfhzi7uZ2aNmuNfvmtlPQ79/bGYfneFe6nIYgaub2cvMLH+732VmlzazXwg4IdCKgAhAK2JqnxF4npnd0MFxTzN7qOAxEYD9fgj4pp7RzE5vZn/YEbJjm9nROnL232b2IzP7DzP7pJl9dQ2Y7tMRgPu765/V9XuzNfrTpXuKgAjAni78mtO+R9jsX2pm1y70eTwz+94a98KqwEfz+2b2n2b2oU7bea+ZvcbMfrZGv3NeKgKwGrpXM7NXFC5lvS+8WpfFq05tZp93GnRuxLN13hXvwwZ/rfTPpczsOBX9QACwDr3IzN5e0d434bsNVljcssxl/WkcmppvEwIiANu0WssYKx/J95nZUdNwvmZmZzOz785AAPpmDKl4ipk9wMx+sgxY/m8UIgD/C8WfmRmbLfKYROKGlqqPAHDNmczs0xOtM5ozGnSUVQjAUczsNmZ2bzM76Rrj+1jqA2JbKyfqSPe/mdlJ0gW/NLMLmNmHaztQOyEgAqBnoAWBY3Zax0fM7Azuoiua2et7OlnXAjA2ti+a2TUW5oveRQLAOrCWXrDM/Hpggb7hNieIwJdGFnOIADyii0G4+9jDUPE737svmNkfTUAATteZ+l+whtWgNFwsabeqIEv5WiwAr3Qdfaqzjp1ngaS4YmnUZBMIiABsAvXtvSc+fsz/WV5sZtcdmE6JALw/+UBrUMC0etzkT4V0HLlw0XfM7OKd+fUTNR0eQJtdJQAt0J3WzD7nLliXAHw9+dN/1TKIQttLpsDVUjctFoDzJ9J7gkJHPzczgjPfklwN3zKzH5rZ8RMhOrOZXS4RhyMVric+4PJm9uXKub7czAgMzPJgM7tX5bVqtucIiADs+QPQMH0+4v/e+f6J/keIOuZjhkbVJyUCcDsze3zDfXPTE5rZDZKp9MThekyoaD5DGukKt1zpEhEAsxub2XPWJACfTcQvd3OVFPux0qKkixgTY0OwHmUXBf9fSwBwdxGXEP38P06uDrIwflAxyFMmFxbjiUTgM8mcXxM/AzHGFYA7AiE2BpcJwYYSITCIgAiAHpBaBND2faAfft07jVw8JQHIt2Lzf3Nn+jxXuPdNuw/6s2snM2M7EQCzJ5rZX6xJAJ6a4giwAiGv6lw9uAlWld8zMywJuLGQ5zoyUEsA6AOy6YkD137czHCFEajaKqTRvtrMojWBZ/yylZ09wcwOdW1xTUCWJUJgEAERAD0gNQjg7yQIK2sqaNp8BMc+eHMQAMaLiRmTP/npWebMt6/BKLcRAfjfOBFP0FZxAWAlQru9TAIW8/8puo3umy2L4drewsye5v7/luH/aywAcaOlO6wBV0hm/hWHdrjGTibA74cOsA6Qbjsm4IvLxb+fpCFi5ZAIgV4ERAD0cNQgED98fWl/sa+5CAD3eUlKu8r3xASLhlYrZ00aJf5cXBm4GLge1wZph5hQ/yWZnSl49NvKjiMBoDDSld21F+vI1PWTiZcPNxoppl6C5vAdk96F9lcjsRDQXbs5/G26kCyNayb/MEV72Dz5Gz7pryQfNSloaK9jMlYICPMzUei1ghYdLTgxCPDJKaKdf2dZJ9XNY0XGCsVz2PSzjBGAaGrnOuJPzrlmTn++/yFp3f03+b8S0a4p8kMwoE8LfGz3XN2hdkHUbj8REAHYz3VvmTUbFFrXsdxFBFO9o6KTOQkAm90jwxjYwCECQ3KWLrDw0U6zrJjG4bEPaJAEMI5JJACYd/kwnyy5KLJGO9QP2iDR4EPxFVwfCcCd09wgNZi40QKHhDoLbLB/NYLbJgjAM1PkP2mmOfiTdWD9WgUc8KtnoXAOFoYPur+NEYCS9g+Re2HrYAbal+5xk7SWY7fhuXqTa0SWBimCS62XMTYf/X4ACIgAHADIW34L/P74/7OgQWKqrAm4m5MA3DptXh7ek3d52WwYfUL0NZYDqrO1CvPFr+qxKPURCQBR2uSKQx5wpdQK2h/+4aH0uUgAbp+0WiLQs6+75n4QDszYRLCXZBMEANM3JnCsLxDOLBfsouj/qWZSrg2R8VSqzEKUPVYX388QAciWEzJSsmBeZz0hUVMJgYGQPp/tQqlfrEZjghUGK5KPJSBFtlRcaawv/b4nCIgA7MlCrzFNzMTXcdfjR0U7rZE5CQCpTg8Mg2Cj6tvE+FjzkffR25j10Zr4Bx8q1oNjmNmpUioWNfx9hDZ9k21A1HWfRAJwWCIcRLEjuBao5Y7pHVM0rgc0dtIpY649pvJzD2wykQDcpfNFYwXA3I+g4WKBYFNhbhAkTN+4JHLUeJ4HGjEZGiUZIwBcg4UDIUjzX0Mn5wvxIrgLMJ97iS6AnGIaiV7L80f/rB8kirK8CIGAf5Awx3+fZYgAlNIH13FH9MB8+J95Nti4sxD7AKa4pcYEywYFmLLw7Ply3WPX6/c9Q0AEYM8WvHG6PB98qMlhztKiVcxJAN5qZpRdzYJGdpqB+fExxGSbhc2cjRBtuU8ukQ438to0vlafdx2vjQTAp5tRuZDfS/5yNlA+/n8aOrx5R0gwh5ckEoB8L8y/XEesRkn+JMU2+Op1bDTERXhTeb62hgDktswjWmFWCQIEC8rronXTH8QMYW7co7YCZDSN4zbC5UF54Xc7cIYIQKy9z2Vnn6n2BMGJZEB4gRyRBTEmEHUIexbeXSoGSoRAEQERAD0YQwgQHEdhEi9jZnbfdi4CQDniD4QkBHuHAAAQq0lEQVR67nw00RZLQmwA2rbXeilq5M3CfTig6VGJLgsbJWZWNqKSRAKQ2/B3SsYOCdYAshuyNk1btGkCzUoSCQBtsGqQPjZEbGgXN0D+1hc4tkkCwLiIZ7iRA6Al5TMSP0gOz3QLAYjFdsjz5xmY0vyfp0eMQ7QwcbrkQ0aeHX7GhRDz/wlepKaCRAgcAQERAD0UQwhwwtgzXAPS/vjI1MocBID7v7NQzpWockzmJeGjSt0CgqL4B60ILbivve+D9vhWvRBL4AOu/G8lAkBVNwLRaqK50U4fHu6H+4IDbKKUCABBad7SMbRWlHDGH56lb303TQCwxPgDc2r94tF68M8p+4L5thCAmNYI7hepfQka2/FNxrrhU1whQAQD1gixIz6dEJeAL8pU04fa7AkCIgB7stArTvPvQrGfHNFe292UBADfPR8zDnPxLgnG0uoX5rmvTeuj//hRHTLLlwgAmj9/rxHq1Mf8bYrqPKmSALAxsUHVCJp0dC9g9aGmvJdNEwDWCy2W+g9ZIFS+3HBpvgRfetz+3AWOthAAXBDeKrNuUaKxtYnPG0SNQkM1EkkdaaFkzEiEwBEQEAHQQzGEQDR9tuYWlwjAP1Zq3owLk30+CwANP5ch9mNGqyMWgPPW5xLM8piOsxBsBzkqSYkAEMiHFlkrBK0RiJjlcZ0Lgwj/KNECQGQ7AWM1GRr0VSIb1A5g3b1smgAwlhj0WePCIfOCE/KQnybNOJfpbSEAXOODRwm2wzo2l8TnjViFi1beLFZhzLEUlZer2T4hIAKwT6vdPleOFqWITJacZ17b09ynAaKJkSrW54+vHedYu48GP/xQBHgkAMQMEETYUigH/z2FYbIQ8Ej0fpRIAHCNcDBSrRAhz8aYy+1yHRstaXNelkAAiNzHv52zMr6aSFIf2aG6HnUDssSI+BYCQAaFr4PBUdRYF+YSAhIhjVkgMjE4tO/e0YU0Vt9grjmo3y1AQARgCxZpg0OMpkhS1cby4P1w5yIA5G8TzR011VqosCqQAcBHlsNdiIYnUJD6AKUT2piHz81uIQCYqccK8sRx49Kg8FAWUgbPUZhcJACtrhC6ZHzetF6yNiyBADDWN6ST9DIUQ0dRPywcIQyBgkhlaSEAFMLyB1CNnYJZ+xz2tSPew2e0tLgASPvz5YMhSpAniRA4AgIiAHoohhCIpk82TUrb1srUBOC+6eM2ViGvb3wE9LExECTng6xq55PbtRCAFu0t90+lwju6QfWlOEYCUGMWj3ONAW7EBBDj4GUpBIC0QAo5Zekzb0PWCLwkYwXhv3F3+LiPFgIQSRIWmpqKjq3PVW5PxoqPc3l+yIIY6pcUVU+MqR8QY2ZWHZeu2zEERAB2bEEnng5ma586h6/dR2OP3W6dIEDSrDiAyOcxvzFErY/d3/9OAR9q7JfOcG/ph7YtBIBKdt6cX3OvWLmO6ouQlyiRALQEG+a+KIbjzctssL7wE+2WQgBwVaDR5meCrAqKHn07AENmA1pzFuovQB69tBCAWI1wFatOzbrTBisUxNtboiCEuN9qhBRQ3pMsYFSKnanpS212HAERgB1f4DWmx7MR85wpTfu+hj7XIQDcJqYh8rfaE9L8MNkkyKePmz+R5USJo6UTeEcQHQWCYobAOjEAmK0ps9siMY6ANEQfhZ77igTg7qFmQc09Yx8UkrleuHApBIBhRetIKS7FH13NWpJGGa1GLQTgH7oKgmQQeIGQQcymlpjySP/UQMAKUCMECxIL4gUy0ZL1UnMftdkBBEQAdmARZ5xCtADUHgKUh7QuAeD5JOebj3UWqpuRqtby8Y0lUumLwipohQTpjck6BKA1MI+xxPTLPo0zbt6kSN5vbDLh9xjoWYojWBIBIGbDn2BIxDxV+bJg7iZtL2u9ZJ2wqUZpIQC4RJ4eOmipiNmyJH9dKPrTVwei1G+sfMg77IM8W8aitjuOgAjAji/wmtOLMQDUxn9dQ5/rEgBuxQcfP7V3RbQUuyECH5+qN4O+IB3sUzsVosmJKs/S4gJg7D6iu+aeVDWkJGwWCIjPxsh/jwSgxVSc+8AK4g8pomDSncIgl0QAGBpVICnklIWzBji6GTm0C9jjVL0sfYVwWggAKZnxUKbWmhg1604bilP5gE8CcfPZDjV9xBgA3uF4xkRNP2qzBwiIAOzBIq8xxTmyADhwhoNnWoRSvGy6XmoDEqNGRB8tefmYT38Y0sBaCMAqH2BiFXzaH4GXzDdKJACtBWp4/0kD9OSIojEUj/GyNAKAOR6zfJZHuecDIkCpaIT0UKrilWpEtBAA+oqpebjHIE6xaFPLcx3blsoz15SQ9v3ELIBWArHO+HXtliEgArBlC3bAw52jDsAqBIAcbLTwfKIbMHwlFedhcx6SaL7FJMqGVlvHvfRRbiEAjI00LILXagV/NQfoZIEA4d+PEglAa3BaqXY88QrELXhZGgGIJX6xYlDzHsy8rx+zvbek+Dm1EoBIOuhr7GCo2vWmHd9iAmx9HQdqHJAOSBZDrcQ6ALzDBMBKhMAREBAB0EMxhMAclQBXIQCMMZo2+RsBfJTJHZI7pHMAcptWjQh3QQyKayUA5PT7MxWGxgvJiR/8vsDH0lkA5PTXpknSb6wTz/0hV0smAIwtHhBEXAhnNOAGycIm74/89XNqJQC4kiAaObUw99WytkPrjuWF2hZeVqk4GCsB8g5T3VEiBEQA9Aw0IYAp2Kcftfo9p4gB8APGFO5rohPZjMZEoGCfxHr3mIMp61pjAeBerwmnDnKfodPZSqWAW0q5kv/vNzG0QMzYpaDHEgF4YDc3jq+tETTYq7qGfScPrmsBqCElHHn7CjeWsRK2rPs7XHviFohRyUdEZ6tAHw6tBIB+SsGAZI1gdme8qwp1KZ7dVWA8quuA4kOQGuJXWoQYHZ91orMAWtDbs7ayAOzZgjdON26eaKa+Rv1Yd1MTAEy8HJWaz4bn/pxfz3G5P+sZDLXgSfPzUpPOSNAfGyxH9H49pOENBdv1HQdcqrEfh0w1QubnXR1scmRflKREAPB7ExUfj4WN1xNUiF/bfwPIiiBnPkoLAQCvmJfPGnBmw5C0EoB4QBDFeUiBy/EMHPVMYaQ+WYUA0FckTfwNMnmPZGlqKflMdD7WJEibXweILUWPVql0iavJWylIpcWSIBECR0BABEAPxRACZyycDIc2yoZYI1MTAO7Jhz3Wqqe6H+lTJUGrQpvykdAQAjbVPtJAIRzS4diQcQEQyOfzwAk0I/K8JKQX+rFQW4DUNCwP1y7413MfFIAhuyGe+kZRG1/Yxd+TmgwXdH/I96KA0lUSOSqNEb8yZXF9nAHEgaA2sIrSQgDI1gBXXzoZTLCaDEkrAaAv+iydssiGTHzDUNzFqgSA5wiLk089zPOCjEKgsFTlQ4dKc6YeBZYXCjf5NchtyWTwQY417xptSjEdEFmeB4kQOAICIgB6KIYQ4PlAm/MFdPDFowXVyBwEAK2JVCmflkcuPxty34l7cVNm7Ji7Ca4jpYwNi8Iu509FV/KmSuoXEeWYaKmR7wXtEj80Gx7t8oFE/B1tMAt12QkCzMFdVKjDXExQI2Va0ZjZjG5d2AzGKh/60+64H4GCaJRUysM0TfEY7oc1gGh/0snwk98qVZzz8xkqItRCAOgzprKh0TIWznCAGEA08FX7Y4dXIQDMB6tUPL9hDDfGuCoB4FrwfdNAeifPI+QMNwSuGwJVIYFcd5aUwlg6c4LrcLnFZ63mXaMNxJVCTllwH/B8SYRAEQERAD0YYwjEIDhy1NmsamQOAsB9S9XSiHZmAy8V9iGAC62dj2+tUEwGfzIbNRozEfZ97ws56R9MHRPI5c9ff3J3HQV62Kxb3CcUuMGkjVbfJz7ljTYQFTR4Nv2W8q+QlJsMVItrJQAxEr00/oskF0v+bRUCwLXMFSuJl5pDq9YhANwLTPCvE4Q6xXcU1w81C3DLrCqx4FVrvYtV76vrthSBKR7cLZ26hl2JABXPfIATGwxugJogurkIAEOPUeD8Dc374T3zopQu86g5VpU8fKK7fTR8qRxsvpUnAI81MzIdsuQcdawAaME157q/tNMcb9tjjvfTw4rhTdG5UBObK/iMEQ7qxIMXZuuhioitBADygZm8z03CHKYiAPGAIAgTzycWkCFZlwDkvqkpgQ8fy0pJqx97zbBaYQ1hvcbGPNQXlihKRntr3VzVCsfmpN+3BAERgC1ZqA0Ok4A7Nn181FnQwCmxOiZzEgCO8MWE7H37mPKpoobptSQ87/jG0RCxFtAHmxXmezR8zLb44TFVR8F0fZekKWPCJtgLggAORN3nKH3S/Qi8yhIzBihMhKmWwDh8tlgn2LRIT6QvTLi15y3EegE+uJF5kb7IfM+VNkU2CcaJ2RzN+bDubAWOnh2TVgJAf9RuwBJC3EM+bhiXB/dGyyWOw/voV7UAxAOCqAL4l2MTWtMFUOqewDs2XNaVoFQIJ9kmsQwv7xLrjOuJMtHZclQx5MEmseDVj5NbC9ePRAj0fhAFjRAYQyBqtXOfhz42Hv0uBLYBAQgn8Rc+q2Ouo4RjdgJxBLffBpA0xs0hIAvA5rDfpjvjA0erziZOzMWcr95S3W6b5quxCoGpEMAFhOUoC64zqhbWWF5qx4CrB2tQfj+pHXH6icsU145F7bYIARGALVqsDQ8V0zim8yyrHDyz4Sno9kLgwBGIpxcyAPz9BF1OJWj73u2h4L+pkN3xfkQAdnyBJ5weGj8+9xxdTgAZqXhTHoYy4XDVlRBYDAKlTIWWdNqhiaDpk0GQqwgSB8N7OVYIajHgaCCbQ0AEYHPYb+OdYz49AWuxTv42zktjFgJzIsBhPFRC9MWR2KhJIaQEMHUSVhUyWwg+zNJ6euCq99V1O4CACMAOLOIBToGIddKW8GFmoXIdGo5ECAiBfgTiuRq5JXUmOG8CSxpEgIJUZIXUHJlNhgdHQGfBQgfZ+IkWQgjUICACUIOS2ngEqIxHmlo2OVIw56wjBWuEoBDYdwRIwSRSP5Z6LuEydhAS11BVkGJRpLIipKWSgkhBLIkQqEJABKAKJjUKCFA2lvr7WV6SctsFlBAQAv0IQJopFc2Jj94dEK8YIwB8tzkoiNoJWYaOqNaaCIEiAiIAejBWRYDysRyDmmXs9LVV76PrhMCuIUBhJMppU1CL/6ZgEIdFce4GLgEI9XMGJk3hKcpLZyGOgJM7JUKgCQERgCa41NghQDbA28yM6nMI+c2ccMZJaBIhIATmQQCtH+0/f7vf3Z2pcEh3SiZZORIh0ISACEATXGosBISAEBACQmA3EBAB2I111CyEgBAQAkJACDQhIALQBJcaCwEhIASEgBDYDQREAHZjHTULISAEhIAQEAJNCIgANMGlxkJACAgBISAEdgMBEYDdWEfNQggIASEgBIRAEwIiAE1wqbEQEAJCQAgIgd1AQARgN9ZRsxACQkAICAEh0ISACEATXGosBISAEBACQmA3EBAB2I111CyEgBAQAkJACDQhIALQBJcaCwEhIASEgBDYDQREAHZjHTULISAEhIAQEAJNCIgANMGlxkJACAgBISAEdgMBEYDdWEfNQggIASEgBIRAEwIiAE1wqbEQEAJCQAgIgd1AQARgN9ZRsxACQkAICAEh0ISACEATXGosBISAEBACQmA3EBAB2I111CyEgBAQAkJACDQh8D9KOGwXVh6OtAAAAABJRU5ErkJggg=="/></switch></g></g></g><g data-cell-id="V1Wl26Vbpgnno5Lb-wtg-49"><g><path d="M 666.37 248 L 703.63 248" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 661.12 248 L 668.12 244.5 L 666.37 248 L 668.12 251.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 708.88 248 L 701.88 251.5 L 703.63 248 L 701.88 244.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 248px; margin-left: 685px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 9px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">HTTP</div></div></div></foreignObject><image x="673" y="243" width="24" height="13.25" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAAA1CAYAAAC+2+58AAAAAXNSR0IArs4c6QAAA2NJREFUeF7tm81LMlEUxo8pVAs1KltI4KYWSRlBELg1WwRCENUf0Dpo3d6WQdSynRCBQgXtRJdu2hSulFYtRESxMBT7wLiXt3n7mGbm3rnqC+/jTuec507Pb849d+5Mjk6n0yF8+uaAAwD65j0fGAD66z8A9Nl/AACAfjvQ5/G1HvD09ERut1s7nfPzc1pbWxM6vaurK4rFYlpOvV6nkZER/v3m5oYWFhaE9MyC8/k8vb6+dkV3dnaWD//dF6Nzcjqd/O/1+/20tLTE/VtdXSWHw/FrGgDoWMPAygDQc3lubo4SiQTNz8/rQugZgEKhQOvr64YX9f39PTUaDR7j9XppcnLSMP7i4oLe3t66ojs1NaVbATMzMzQ6Oqp7Xq1Wi8rlMpVKpS/Hh4aGKJPJUDgc/pHXMwBm0wk7zkr28vKSh25tbdHZ2ZmVNNMYO7oyUzO7kI6Pj+ng4IBfIOwzMTFBd3d3X6Z59jsAmOCTAfAhmUwmaXNzUxshHo/T3t7elxEBoIsAmPTKygql02k+yuLiIl1fXwOAyNRmpwKY02wq2tnZ4aazVdLz8zMNDAxoEFABXa6A70vzarVKY2NjAGDauf8E2K0Atqj4fD/1+PhIHo8HAHoF4PDwkHZ3d/lww8PD1Gw20QN62QMikQhls1lu+vLystaQPyj82gPYLfXg4KDVC4XHtdttenh40HI+b0VYEbKzXjfSt6NrZwpKpVK0sbGhndrJyQltb29bqwArhpnF/K8AarUaHR0d0f7+Pr28vHCbgsEg3d7eksvlAgA7U1AoFCKfz6d77bElZqVSoWKxSJ+f9I6Pj1Mul6Pp6ekfeViGCi5Dzar++3G2/3N6ekqBQEA3FQAUAmDbzmwTkW1HM+PZNkQ0GjUcAQAEAcg8JzEaAgAA4K8DdpaL/+Iy1Eq/QAWgAlAB/NVEO3d8HxYaPZS3Uo6Ygrr4VgQA6DuAHoAegB6AHmBQBSp6o6UbMStzNGLUO4DX09V7KqQIAEJ2qQ8GAPWeCikCgJBd6oMBQL2nQooAIGSX+mAAUO+pkCIACNmlPhgA1HsqpAgAQnapDwYA9Z4KKf7+73tCMgiWdQAAZJ1TlAcAioyUlQEAWecU5QGAIiNlZQBA1jlFeQCgyEhZGQCQdU5RHgAoMlJW5h0DqhjC399QigAAAABJRU5ErkJggg=="/></switch></g></g></g><g data-cell-id="SsHHCok0RUWS7ODwTELy-4"><g><rect x="530" y="228" width="130" height="40" rx="6" ry="6" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 128px; height: 1px; padding-top: 248px; margin-left: 531px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Search Service</div></div></div></foreignObject><image x="531" y="241.5" width="128" height="17" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="S3Av5TdVFqS_SrXukbwN-1"><g><rect x="180" y="132" width="130" height="40" rx="6" ry="6" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 128px; height: 1px; padding-top: 152px; margin-left: 181px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">UI</div></div></div></foreignObject><image x="181" y="145.5" width="128" height="17" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="V1Wl26Vbpgnno5Lb-wtg-26"><g><path d="M 710 224.6 C 710 219.85 721.19 216 735 216 C 741.63 216 747.99 216.91 752.68 218.52 C 757.37 220.13 760 222.32 760 224.6 L 760 271.4 C 760 276.15 748.81 280 735 280 C 721.19 280 710 276.15 710 271.4 Z" fill="#e6e6e6" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 760 224.6 C 760 229.35 748.81 233.2 735 233.2 C 721.19 233.2 710 229.35 710 224.6" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="A18w2Y2_AVEIFkgUy5Lv-4"><g><path d="M 766.37 344.01 L 790.06 344.06 L 820 344" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 761.12 344 L 768.12 340.52 L 766.37 344.01 L 768.11 347.52 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="V1Wl26Vbpgnno5Lb-wtg-32"><g><path d="M 710 320.6 C 710 315.85 721.19 312 735 312 C 741.63 312 747.99 312.91 752.68 314.52 C 757.37 316.13 760 318.32 760 320.6 L 760 367.4 C 760 372.15 748.81 376 735 376 C 721.19 376 710 372.15 710 367.4 Z" fill="#e6e6e6" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 760 320.6 C 760 325.35 748.81 329.2 735 329.2 C 721.19 329.2 710 325.35 710 320.6" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="V1Wl26Vbpgnno5Lb-wtg-33"><g><rect x="692.5" y="376" width="85" height="20" fill="none" stroke="none" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 89px; height: 1px; padding-top: 386px; margin-left: 691px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">metadata-db</div></div></div></foreignObject><image x="691" y="379.5" width="89" height="17" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="V1Wl26Vbpgnno5Lb-wtg-34"><g><path d="M 393.5 413.6 C 393.5 408.85 404.69 405 418.5 405 C 425.13 405 431.49 405.91 436.18 407.52 C 440.87 409.13 443.5 411.32 443.5 413.6 L 443.5 460.4 C 443.5 465.15 432.31 469 418.5 469 C 404.69 469 393.5 465.15 393.5 460.4 Z" fill="#e6e6e6" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 443.5 413.6 C 443.5 418.35 432.31 422.2 418.5 422.2 C 404.69 422.2 393.5 418.35 393.5 413.6" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="V1Wl26Vbpgnno5Lb-wtg-35"><g><rect x="377.5" y="467" width="85" height="20" fill="none" stroke="none" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 89px; height: 1px; padding-top: 477px; margin-left: 376px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">data-db</div></div></div></foreignObject><image x="376" y="470.5" width="89" height="17" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="V1Wl26Vbpgnno5Lb-wtg-36"><g><path d="M 220 412.6 C 220 407.85 231.19 404 245 404 C 251.63 404 257.99 404.91 262.68 406.52 C 267.37 408.13 270 410.32 270 412.6 L 270 459.4 C 270 464.15 258.81 468 245 468 C 231.19 468 220 464.15 220 459.4 Z" fill="#e6e6e6" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 270 412.6 C 270 417.35 258.81 421.2 245 421.2 C 231.19 421.2 220 417.35 220 412.6" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="V1Wl26Vbpgnno5Lb-wtg-37"><g><rect x="202.5" y="468" width="85" height="20" fill="none" stroke="none" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 89px; height: 1px; padding-top: 478px; margin-left: 201px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">auth-db</div></div></div></foreignObject><image x="201" y="471.5" width="89" height="17" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="V1Wl26Vbpgnno5Lb-wtg-38"><g><rect x="530" y="132" width="130" height="40" rx="6" ry="6" fill="#e6e6e6" stroke="#000000" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 128px; height: 1px; padding-top: 152px; margin-left: 531px;"><div data-drawio-colors="color: #000000; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Storage Service<br />(SeaweedFS)</div></div></div></foreignObject><image x="531" y="138" width="128" height="32" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="A18w2Y2_AVEIFkgUy5Lv-3"><g><rect x="780.5" y="358" width="108" height="20" fill="none" stroke="none" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 112px; height: 1px; padding-top: 368px; margin-left: 779px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">metadata-db-data</div></div></div></foreignObject><image x="779" y="361.5" width="112" height="17" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAcAAAABECAYAAAAWc+UJAAAAAXNSR0IArs4c6QAAGf1JREFUeF7tnQOwLjsSx3tt27Zt2/buW9u2bdt4a9u2bdu251eV1PbpDeebmXO+O91Vt96798vMJJ1O/q10DiBOzgHngHPAOeAcWCEHDrDCMfuQnQPOAeeAc8A5IA6ALgTOAeeAc8A5sEoOOACuctp90M4B54BzwDngAOgy4BxwDjgHnAOr5IAD4Cqn3QftHHAOOAecAw6ALgPOAeeAc8A5sEoOOACuctp90M4B54BzwDngAOgy4BxwDjgHnAOr5IAD4CqnfU8N+n4icl/Vo7eJyMX3VA+9M5YD5xeR96h//JuIHDzDpgeJyD3Vb28SkUvvoyx978CX86mx3X3gy8P20bHuE8NyANwnpnGrB+EAuH3T5wCYnjMHwC2TZQfALZuwfbC7DoDbN6kOgA6A2ye1iR47AG7PNF5XRE4Quvs4Efnt9nS92NO9DIC4sy4Qev9aEfnsPsLzTYfhALh9AOiy7AC46brf1ed/JiJHDT0ACL+7q72Z7uN7GQBfLiJXCUO9vog8b7phb/WbHAC3DwBdlh0At3bTOZGIfFP13gFwman8gYgc2wHw/5jtALh9AOiy7AC4zK45w1euIyIvcACcgbP5VwJ8bBqR3AL8Hy8cALcLAF2WM+vcY4CL7qmjP/YUEbm5A+Bo/o158Koi8jIHwCTrHAC3CwBdlh0Ax+yBe+aZz4jI6R0AF52Pxw6JRrdzAHQA7JC6vXoMwmV5ywDwoiLCgehIbxaRS6m/n1pEbhwy9IiHcQj3DyLydRF5u4g8VUR+khjzgUUEbYjEhjMO7Y4mIv8SkV+KyKdE5FUi8hIR+XeH0MemvJt+X0xEzhXefWQR+aeI/GLo749EhAXylqHdhyvv513/6OjD5wxAph491ZDFePnh+2cbLJtTiMiRROQwIvL3kFH6vYHHnxCRN4jIu4bD6f/p+L5uelIRuYaIXEJEjiMiRwnfYPyfFpHXiMirA194bpMkmEOF78BzZAJZYEwHFZHfi8ivRQTefEhE9heRn1fG9MEwd61DP0IlG3fq/rX2q7cdsnC1IB8nEZGjhxcgt18SEdYfLvjfhX/fxAJ847DWLqM6SHYi8nL2MH+HFJHfDB4Pkr6YD+SFNb0bdN6wX/DfY4jI4UXkTyLynbCGXxxkK/ZtEwDk/ZcLB+lZq/wdWcZLR8b3T8Me9e5B1l8pIn9dWJan7t9uzOf/fXOvukDPYUDi/UEw6C+VJaiwUOo7Qrpf2GjjoNkgcWmdssJ5gJBKFQhcK7F50K8TNz7wARG5k4h8PNN+SgBkvGiAgHMrfWWIf91wAPOPtD4gIgcb5uT+gyJyx4EX9L9EXx2Seq4dFjRVYADBSC2VYA44ANwdghwcsbGPAP2TBzC+R2HzmAoA5+pf41C7mhFf5lhNjY9swrceZPxFYS2y2UfqqQTz+rDRA7LPb5RLNn0U3m93jWx8Yzb7pw0K22UbXoFyQHwY5YrqOCgHkVoqwaBEPSSst4M0fI8mKHZ3GRTMZxfaTyXLc/WvcajzNturAHimAYQ+qYbO/59FRB4ZgKOFK2x4WGI8e5rBWnyfiDCZLYTLke9hHZboQCLypAEsb9byUtMGy/AGIvLCxLNTASAlxV4hIoce0T/Gfs1BYSB9ukZs+HznirWG6neUlAuHPw9U/14DQKw7rIJLdnxLN/2YiFxw2ED+nHh+ik1jzv6NHHL2MVy8KEc9dJsBwFgfKHGRegAQ6/+mQblqVRj5zo/Dep77+A8eCzwGWMKthOfpnEHBvpB6qAaAxx/G9I4Oxdn2h70HpSRFU8jynP1r5e2s7fYqAJ7OHDr+4uB6uHNwH8IQFuBLw9EANt+TB4vPCi0aGdYcB5j5DbciGzUaJe6dwwbB5ZA5rhdNaJzPqnCfc2E8qwlNkOfQkHHDsiEeb1hUFwlt9XdwM149AzLRDcWC/Lz5xllNhiLj+pVpw+aCNcsYI/E9AIY/HKv4o4gcIvQPlyW8gp+R2NhQRnCDlegBg7Jwb9MAi+GZwX0FH3AH4qLE/YXFDMizqWEFsFFEqgGgTQjiOd6DPOBihf8oF7j1cHNj4cSjDPEbWDH8uyWsIOYLYoPXGzRgoZNiaIObzrqK5+xfZRq6fmajZvPVewCuf1zFgFQEmmMGJQU5hz8oRlj5WI1aTlprgeI2RCGL1hWud0IPXwiWDfOGmx4ZweWoCXc2czomRNHKHBRlXJ6avjG4JJ8+uNtRnrC+UKTxKNHHWCgB1y4WHO74SCUARM54n47t8xxjhB9fDq5g1iMW6XmCq9gqszfKWIKbyvLc/Wudj1nb7VUAPG0QhDh4FiMWHfGluwZL0G48CN/rQkxIM40NlsX7/RBHBEwtnSxofSy+SNHtmpsAgIt4oSbAFdch8cgUsZlgvQBgkYg/EpPjvykCCG08s+UcIBsNsZVIgBngw6aXIxYzC1mDNBVQrlB4BnBBAwZII7F42Qh+mHmO+eU7xAiJ92jLvASAKDqAsQZpiisT101ZdHyefgF42jpFdthIS5VdcNMiF5FajkEs2b/ClFR/gn8okcxDJCxylCBt2ekXoYgh7wCnnbMeC5D4WaxohOJE6CAV70buAQIsK014TZ5bHeG4BlcOCrJ+GqWHuf9L5pWAIPFRAMPypQSANwmgql97n8CPXPwdRZr1oeWSveGElZjgGFlesn/jZmuCp/YqAKJdoRFaevgw0XcrjJuF9a1EfJAFeoZBYyO2lSPe+1D1I4sSqyW1OIl3AaixMguPkdyCBVXTTtFq0fKOq771xEGzxLWUojEASPAcTVXH4hgb8a8aYWk/QjXCmkKbzIG6dUvDL4L4aM0lIjbJJhwtrti2BIDMP7GPSGza8JGxlghAx9IgKSlSTZbGbBpL9q82j6XfSShDAdF0vWCNl57D+iBRCqDX1AOA8TmAz3oN7LdRSFFYozeE3/GG4CGagxjbmdWLkQH2jVrCCUpvyltUAkCsP60IE2+3YJ8aI6EZmzuA4vLWAkPGyPKS/ZtjLpveuU0ASFIKmk5OE4sDRqu3C+QxwW1TYgqL2gIkQJxy/9mD6WwAgG8q8zT1TSwzLLRIaI64OXiPpTEACLjgogKg+cPGz8IBeGtEe1x7mogl6qxc/RsKB/MSCW3YuoVz33x8AvhLAPjgkGQQx4Uru2Sd6u9a1+RHhzGRbJWjMZvGkv2rzWPp9+cEqya2wSojRFCLedMefuMi1dQLgCiPfA+vTo1QeFAsNOGaRu6mJKwrG19stTbZR3G/W3dmDgDJHYCHeISQZaxr2rIeWggPC16jSFy5pMMI9h29srx0/1rGPEubbQLAFhCDSdb1x7+RBJNyfWqmMumAq87EIllC33sW23NMgN8iEQvETdJKWGYAuna5XimxsfC+MQBo+8E89xxrIKYGIEfKbQQsQhajJo5a4IpuITYMrEBNtRigbtszLuvSYRNm08tR76aRes+c/Wvhb66NritLG5Sl2ze+kHXC81p2ewEQyw8LsIVIxACgNVEUgizNKYl3oiRFwpOD4ohy2kKphKJaEsxYWbZ7XE3pXFqWe/vXwt9Z2mwTABI054xajR4dUuRjOwS4luId23JWDa0sUuqbbACch8I9GokYFPG/HiK2wHORcCVq91789ykAsKdftEVZwI0ZiaQHFBBLtsIEv8Pr1k2D9ljN2sXVA4A947LxHVy6OkHIvmuKTWPO/vW8W7dNWfjER4lNtxKxQGLgkXoBkPirVXxK38Yy08pKKWTQOgbbznoIel2txOWQGU09ANjTb7I/b6keYF8sHdlYWpZ7+9cz9knbbhMAUhC65RwQKfX3Ulzi0DnHIVqIuJXO/OPAPIdONdkEHX7DnaOLVbd8i8XB+Z9I7wyZovbZ3QBA60YmLvioxKDsIXYyUXWcrYUP1pqeCwCxTPUmT/ywdDxk6U2jt38tvE21sYfYadPiIdHvwoIjgSVSDwASUyYm21PogcQtjszU1spYnvCcPcROAg5KUyuhGJOIpWPacwEgFvttVcdIBCP/IEdLy3Jv/1p5PHm7bQLAVsvCbsq2ikyJiVZQUgBItQYyIzWRVJDLQsx9j2w6DdRYnzZdn2enAMDDhQxQNG/imlTAIVEGANAZlbGvJOqwoCPlAJDAPwkAkYiDcGyihzgqQSp3pB4AJGGBjZENHCUEi45xkaRkiY2J3yItAYBz9q+Hx7otBQjs2VP4lktySn3nWiGzNv7WA4Aoij1n7PiGlTMS5HQG61he6OfoF0p2pNaQi36HVaBbAZCQCMekSIJBlknsQlb5kyoqgfdJHzuZGwDn7t8U8zfqHdsEgKSz17KxYIIFwB5NrgUASfCY41643Ia8CQDi7iJATtJN7pxWi+DkANC6cTlDpSthtLybjUbHn1oAEM2chBOOxYylOQFwzv6RMNHjrsQ9ppNIbKwL/qEE9cSIcbfpOG8PALZmO+p5tbUsiQnqxCvacg40pUCm5IPjOdqFSxsbF6Wqka5Q1CJnKIBkjUaqASBKGWuL+GGv50T3Zy4AXKp/LbydpY0D4E62tgAgxxVas7V6Jw1Ny2bijQVALDFqKLbGP0t9zQEgC09XZCEVm5TsHrIu6xIAslFjDfQkHOX6MgcALtE/e7VNjdeUy9IWtj3mglKpz3DW3sfveC9w2UfqAUBc3tqd2fI9lB19hIciFvoIEu+wFlzpvWSQ2io0yIM+/8qxKJt9WusrZyjP3QiArEt4qAGz9v7c73MA4JL9GzvujZ9zAOwHwFuEmpIbMz/xAlyVFHHWNAYAjxXOS1nww0VD9hxaOIkFJKuweVntvzUGyNlHjkhEarHe7LDt2bnSO7BmKYSgiZgSWWdYJCTvkF2LO5p/19QbYxsTN1mif5sCIPyjn5FK4JWTcZQcQgst7yDb856qLTLTW8bOvgNrTSdO8fpNAZAMcO0lqVlvKd7Ys3O5d6AoAZb23B/Vk1ifKAmsVYAeBcWeLe6NsfXK8tL9m2MvbXqnA+BONrVYgDb+gXBiufW4kJomJzQaA4CpEm0k3FB42gJDqi+tAEiCEMc3ItWq56S+ZTPGcgBI3IgzmfqYCkcZAOBSgYP4zbkBcKn+bQqAtxqOMJBFqYl4b62Ag25vM2p7LMAp3OSpOOKmAEglJn20gyQf1ksP2ezpHABSdMBWs0HuCVW0ZFDPDYBL96+Hx5O2dQDsB8BUFY3eJIKeSewFQNw4VEbRiSCkrVPYupUAFF3tI+cCtUBLajuJNj1k44g5ALSuUjZsEnpawI/+ULKKOFGkqV2gS/evh8e6bWpzS3keSu+3ccQeABwjIzZRCgVtCtehHqM9akHckRtHesjGEXMAaF2luGRJfqkV+Yh94bo3XYB/ahfo0v3r4fGkbR0A+wGQxIuvmVkgIy1Vum2KyeoFQHuXIn3oOXeF+wM3rD7nmANA674EeLUW3TJ+a23mAJDjLLpyS7xWp+UbtLGuv6kBcOn+tY7btrPuS37vlV9rgfQAIGdobZHr2liIZZMlGcneKVh7vuV3676kUov2btTegRKBC1NTCgCJt5Jxq7OsAdqeWzls6GFKANyN/tV4O9vvDoD9AAjP2Oj1Im4plDx2EnsBkKot+p4wzlsR22h1cRHEtwWRcwCYsibIZrM3U+TGnrJWcwCIu5Pi2ZEoHKyvUarxl4QDfVXN1AC4dP9q4839nqqsgkuTbOlWwtXN7QSRegCQZ3DjcuynlTj/Gwto8wy1am0suPVduXbWm4E7E6uslagMRexOUwoAyV61Zdy4fSJXhNx+H4DC0tRHeqYEwN3oXyuPJ2/nALiTpS0xQJ6wGlitEsMmE9cLgByQ1VfVUNaMpJhWslU+eC4HgKnCvLmSbqnvczsFlpymHAASG9FKB6XNcI21ECXb2ND0mcepAXDp/rWMO9WGNY8Foi38nsoq3NxBcoa2YHoBkLOj1CNtIZQelAtN1OLlho8pyWbHEtPnyEmrMmcrUNG3FADaq95oh1epVjw+jpW7FG0ZuCkBcDf6N+U8dr3LAXAnu1oB0F6FRGIJ2qIthVSaDALsVKjBvcMfe+dffDYFgKWqONYqY6MnRtliARLfBMytXJDFp6vWxL6l6kISZ9PXMJV4YF1btM0BoI3RYAHoWyty3yFBicQLm3FHIebUgfn4HisLtU176f51LXTTmEIOFHSI9INwCLylOgvHETiWoKkXALF27J17ufHYGpscE6JOLSA8JaXq0hJn4x7AGmGNcTbRuv9TAJiywLn/0N7wkPomygAxVPsdKuUQ+shRjyzvRv9q/J3tdwfAnaxtBUAOiKKVUlElErdI42JL3ehgJ5AKIdzYrDfgXBwGYbd3BZ49XKaZEgx+45iDJoCWGFWJSHqhT3yPowQ6zbyUEGBvFmCD4gxi7eaJ1N1r9C8HgJwx1JeN1hY970K+nzDwj8xHOyZ+LyV/ENMlySZS7VzY0v3bZFPYL3H1ETeLk5FbIjJd2ahtDK8XAPlGi6cAYCHzV7u+KU6vC9Fvwgf7rHW1AmpYRLUqOTaTOb43BYAoZMQKtQWeUzB1/1BikTHi4FaWa4lFPbK8G/2bcg673uUAuJNdrQDIU6lC0GzKVIopXYvEdTLE6PQlsBwnoOxaihBIzgJplxPWmD5bpZ/jmAC3outNCkBk08hV0mEsHDBnw8EFSqKCzjLjnjR9d5n+HpozFTC0LHH3Hu7NXGIQLqxnhNgk8RBdgioHgHcKFyHrb5dungDIqZLPmTMsG5I/9OFt3oPFq8+z6Xfbm8FRDrBacsddlu5f10I3jYm9comxdo1jEXPEx9a+jY8y/1j38c5NPWclAERW9VU98dJYPBPIPOGEFFGmj+8xR5pqd99twhcbPuBdrGk8GilXKAos1jDF4iEAVFeoyWWBksSjx0VOAUqxvfUijgXlmHlBAeEbxL71MQrkG3ct6zZFvbK8dP82mbONnnUA3Mm+HgDkSYQQl6OmP4aFy8Ih/sbmQGIIQozWS9xME8kAZGkCWjnCmtK1D9mE9x/OwHGnHcBIVQuq2UcXrN10eC8uVlyGaPAAIZU0cL1QGzJmV+LGYyGy4O1ZMS7UpYYkgEw7rRWnzh2yoVKyi8QAgvZsaPQTBSDemwb4YV1qyyNn2XGoH2DVBaxxPWPhcRMH5a1I9iGewiaJIhITBeJtFrjNdMkpvg/Q81+sep3dm7qrENcdMct4ES+8jGXJlu7fRgs/yG3qZnU2S4oKwGtki4QVzlpSvYUYKvOKwqTr4bIB24uNY/+QG32JNbE73hlL5qGAkIDDcRYsIxQXErGI8erEF943ptJQD59QHrE4ba1SPDCAMYogAE4fkWHWcyy/xnpkXbKeIuUsu1SmNrJJgQLkPybZsea5qYM1w1zA+/OJCHuMVS6JA1K+DR5SCEInGfXK8tL965mjSds6AG4GgAglQMG5qDHEJoOwoY2XKHUpqG1PVh5WCoSGz2LlYtxWwmrFhctGhBbLweKcfADin1Qvxp2DdYX7tZUAUDZBXK9sHpFKLq4xdVj1XXcpoI7ftYkEKAcoGCWy99ot2b9WPpfaoTzg+uwhgAle6Q2WjT9VVJ33cs0X1nEkYmps1HglSvcx2j6RxIQF3nJQvGc8ti3XGrGOempzcicmMWbGemP1QuL8+tYM/a2U8lzqN0oGFjrKHusSS5B4XYps0toYWV6yf5vM10bPOgDuZF+vBRifxpWDW4LF00JYYLhBSSiwpc9Sz+NqIfU854bkGQ2A/J0YHpq1Tf5IvZ9kFJI8sKIi2cO2+jkLgPyGyxVrzlrEqe9haWFlEruwmaC166vYgNm4SwksfBN3EIoDrtZIaPafMink8bdUJl1Kc9bjSV3sumT/WmSt1Ib1D484UqLrYKaegZ+UAaTsHJa1lVsswFQSjQVZrtVig8ZyQvFpSYbB/cf9dyUvyaa80M+TNUxIoGXtYMGi+GAl2kzQWqgCzwfyUiMyRDlqRZ5BJJuIp9+RytrulWWs4SX7V+PBLL87AO5k61gA5C1Yg7iJsOhw4QBA+OVxGeKyQGPGvfLu4D7qXcxYWWjSgG2Mv+DuIBmHTZ1YhD1bxfxSuZ8qKGiBJO0AHFhfWHiADa6dlKXDeHAdkjCB65LNDYDk3jQ2zFwWHu5cvoc1SYwJTRrXDe5g+onLEGCOJdnYZPTCbrnqhkuLcV3yDVyegC/9w9WKqxdXGZtrSrkgWxcLhI2XxAJiO1gXKCS6UkyUDDY3tHrcUbhYAQKSEDjAjzUTrW4tSUv2b4qNATBCISEuhfWP3GLRMcfMB/x8vjnojWtfuz1xC+K6s2STpKxbkPWCSxXvAdcAAcRYecgLskaloFoC1xQ8sO9g7RA/xgVJiIC1Q9IU7m9idViwKAP6/J7NkG05XkJFG4qVI4/MA8oFLkwyc/Gy4I7mjy2ST3/J5GVPwB0LYCGXHOjHEtUemk1kecn+zTGPxXfuVQBcnBH+QeeAc8A54BxYFwccANc13z5a54BzwDngHAgccAB0UXAOOAecA86BVXLAAXCV0+6Ddg44B5wDzgEHQJcB54BzwDngHFglBxwAVzntPmjngHPAOeAccAB0GXAOOAecA86BVXLAAXCV0+6Ddg44B5wDzgEHQJcB54BzwDngHFglBxwAVzntPmjngHPAOeAccAB0GXAOOAecA86BVXLAAXCV0+6Ddg44B5wDzgEHQJcB54BzwDngHFglBxwAVzntPmjngHPAOeAccAB0GXAOOAecA86BVXLAAXCV0+6Ddg44B5wDzgEHQJcB54BzwDngHFglBxwAVzntPmjngHPAOeAccAB0GXAOOAecA86BVXLAAXCV0+6Ddg44B5wDzgEHQJcB54BzwDngHFglBxwAVzntPmjngHPAOeAccAB0GXAOOAecA86BVXLAAXCV0+6Ddg44B5wDzoH/An5Gup+Cx6S0AAAAAElFTkSuQmCC"/></switch></g></g></g><g data-cell-id="A18w2Y2_AVEIFkgUy5Lv-6"><g><ellipse cx="834.5" cy="344" rx="14" ry="14" fill="#e1d5e7" stroke="#000000" pointer-events="all"/></g></g><g data-cell-id="A18w2Y2_AVEIFkgUy5Lv-7"><g><rect x="780.5" y="262" width="108" height="20" fill="none" stroke="none" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 112px; height: 1px; padding-top: 272px; margin-left: 779px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">search-db-data</div></div></div></foreignObject><image x="779" y="265.5" width="112" height="17" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="A18w2Y2_AVEIFkgUy5Lv-9"><g><path d="M 820.5 248 L 766.37 248" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 761.12 248 L 768.12 244.5 L 766.37 248 L 768.12 251.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="A18w2Y2_AVEIFkgUy5Lv-8"><g><ellipse cx="834.5" cy="248" rx="14" ry="14" fill="#e1d5e7" stroke="#000000" pointer-events="all"/></g></g><g data-cell-id="A18w2Y2_AVEIFkgUy5Lv-10"><g><rect x="364.5" y="538" width="108" height="20" fill="none" stroke="none" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 112px; height: 1px; padding-top: 548px; margin-left: 363px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">data-db-data</div></div></div></foreignObject><image x="363" y="541.5" width="112" height="17" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAcAAAABECAYAAAAWc+UJAAAAAXNSR0IArs4c6QAAFIJJREFUeF7tnQPwLTsSxvutbdu2/da23tqsrbVtG7W2bdu2bdvW/LYmu71dmZnkIHfmf76uunXfuyczSb5k8qU73Z39TCIEhIAQEAJCYAcR2G8H+6wuCwEhIASEgBAwEaAmgRAQAkJACOwkAiLAnRx2dVoICAEhIAREgJoDQkAICAEhsJMIiAB3ctjVaSEgBISAEBABag4IASEgBITATiIgAtzJYVenhYAQEAJCQASoOSAEhIAQEAI7iYAIcFnD/m4z2981+a5m9pBldWHnWnsfM7u36/VbzOziAyi838zO7X67o5k9Yo8i9q/Qr3N2uHx4j/ZV3ZopAiLAmQ7MQLNEgMsaL1orAsyPmQhweXN5z7VYBLisIRUBLmu8RIDD4yUCXN5c3nMtFgEua0jnTIDXNbMT9nA+xsx+vSxot9ZaaYDL0gBZE+9hZgfu5zBzWbJHERABLmtg50yAPzGzo/VwQoTfXha0W2utCHBZBHgqM/tC3+TvmNkJtjYz9OJ9joAIcJ8PQVUD5kqAJzazr7ueiAD/B4YIcFkEeEMze7oIsGpdWmxhEeCyhm6uBHhtM3uuCDA7mUSAyyLAZ5jZDUSAy1oYV22tCHBV5PbNc3MlwCea2c1FgCLAis9irk4wXzSzU4oAK0ZywUVFgMsavLkS4KfM7AwiQBFgxec0RwI8gpn90uy/18TpDLBiQJdYVAS4b0ftfGZ2VTPj72OaGR/gH8zsW2b2QTN7oZl9wDVxHQI8tZld3szO3u9wj2xmhzWzv/bebnzsHzOz15nZO7rg7bhAeaQOYmZ/q4DuM4Egc49usn0VTasuejIzu7qZXcLMjmtmR+0x/IGZfdLMXmVmr+w8Cf/ev3kdE+gdujF6ZP+eg5rZlczsCmZ2RjM7tpnxbz8zs+93AfRv68b1JV2Zz1X3aP0HaAftumLftmOY2SH7efXVbn6/s3MmebaZfdNVtSoB4p15XjO7TD+nTmpmhzezQ/ffDt7HXzazj5rZi7rvC41uTC7cY1eKwmO7ft1movBS5nJpn/dsORHgvhlayO7J3YJ52YLq32hm1zezn3ZZYN5lZud3z5RkgsGr7dEdoV60oK5U5EtmhjPAhwae2SQBbqN9FV0tLnrwTjO4r5nd3szo/5iwAF+rW6Q/0WeBgQST1GSCuV0/dmxanmdmLPZj8s9uI/UUM7uTmf2+uGfrFTybmT3TzFj0x+QfZvYoM2PO8t+rEOClO6J7uJmdoqLJfD83MTM2KDnZJAEuZS5XwLe3i4oA248vGgNa3dRi5lvGLvpc/Q7/Qu6HKQIk5dbLunRah1mhmyxS1zCzl2ae3RQBbqt9K3R39JED9Tii4ZQKmjyLK3/uvyIB3qonUbS7Q5VW3Gtcl+zI5i8Vz6xSlDn59l7bK33+5b3VAwsC2lySqVRoxOZ5HEvro9zPu3aep9Pcv5J5aFMEuJS5XIPbni8rAmw/xO/pTZ6+5q/1O/eP9GcQRzSz05jZAWZ2gb7g63uT18UKCfAk/eJ5OFeeXTcaCH8IW0BLwFR1/N6kxw6bxT4JC+iZXVyUbzNmLgRC/2yAEa3ge+7fWOx+Ecpsu32bHNn7dVrLPcMLMbU9rduYvNXMftSb4Aj/wDTHuLFJ+GGXHOA5vdaTHq/RANE20QIxdyIfN7PX9qZExu5Y3WbqIn2dUSt9Qof5LTcJQnjXUXpCOVL4d8z09BnTI5sAYkMhSjyFT96XxbT7QDNDq04yRoAcE2De9fKnfnNG/lTm2p87DZO5jgML5Zm3Xr7Ra6lxU3AwM0t9uFxvmUnPYVo+a3gPffrdgufyFqfE8l4tAmw7ZlfuNQlfKx82Jk4+6JywmBJiwIf6KzODHJOMaYCcH3JWlYQPn8UZbWJIIFuI1msbr+7Pd4aegQghAC8lcYCt2rfuCB+n04TRwNkoJGFxZyPCApmT0/U4ckYYx6yGADkLBksWXFzz0Z5ywiLN2e3R3Y+cQWKWpO3bEAj2FuHFyWSbq49zwgd1my7ID/I+RDAlDxEgz7FBZJOWhLNELCFjyRYwAz80NISzO87whuRq/blh+r3UCWYpc3kb82DR7xQBth0+nEzO4qrkrAiHBnavY+KDc325IQLEuQVvNq8VPLhz1rhbQXe5geBhYSFlhxx3vanIKgTYsn0FXR4twpkTi3YStFmIhUV5TDgPwjuWjYuXGgLkObR2yHZs40I5THzvC3U9riPgW68LQOZ5nLU4k4ackuDkwkZuSjjL5Hw0yhAB4mzEOZ4X8EDznpI3dM4wmIKTYGE5x8hDqxDgkubyFF4797sIsN2Qs4ONO1Z29c8qaALjhIehDzXgsSECZPElhyHmJ/5grkJLwBtzSihPWjMvnG+wcOdkFQJs2b6p/k79junsRK4Q2jh5T0sEbYNzPC+1BPjioMmP1QtRQBhJMA0er6ShlWWu05s502OQNGfaYDUlmG0phwboZYgAsYAQY8q8xNzOt8DfY17K6b3RdMq5NmbSPw40chUCXNJcnhqbnftdBNhuyPmICRhPgscexISJrEQw3+DN6WXKCSaVZZxLFoxUnrMrPFWTjBH1KgQY+7vN9pVgO1SG86ToRk8oyWsKX8qGBS3QSy0B4vLPOVeJXC+zoaIPWBo2KZjtIZckn+4tGaV1YFbnvM3LlBPMKnOZkJXo+MJmBtNyTlYhwKXM5dKx2alyIsB2wx2zpeA4cvqK6nEgiAtZKQFWVPOfop8Pbu04Y+DCnpNNEOA221f7bl8+53yBObh008K7OB9NDkP8fw0BUg/aDppLiZC4OS7uxA4Sl7hJ8dlSeG+tqfWmwdmEd5QSYE0/2GASJ+kF5xisKTnZBAHWtK/2W6t9t8pPICACbDdFYhD7KzqiwSmmVHAZx3Tjz5S2RYDs6D05j91Mvi8IsKZ9pfjmysUgdjxZWVRrhKQCF3QP1BAgHsM+7nOqXjx4cabyc4TwATwuNyWc++EJ6c//8DbFKaZU0GrfGwpvgwA5q4ybFY4C8KadCwG2msulY7NT5USA7YabsANuTUiCRoVmVSM4XhA+kKSUAMmUgQfomfrwCrwFObwnPtCHPaT3snD4GK1tE+A221eDbyzLrQA4ICVBc4ju9VPvJ1TiRq5QDQFS/42nKgi/x3n2+Mw5ZOUr/684XrE+xIUfSeiAF2qpENYRPWhLCZCzdMJ18LTl/A2vaOYynstxPeP/Y5jGtglwrnO5dGx2qpwIsN1w+/vyqJWsIj5DSElLWIDxGi0lQBwHHtI7UUSng5L6UpltEeC223fnnvhL+0o6L28yi2ddtRoZ9bLRue2KBFjquev7F/Oy4mSVbjegHCZV0rWVCsTmwwly56KEz2DhKBUcUX4TCk8RIOepYIlGvM66tS0C3PZcLsVW5SoQWGciVVSjor3ZyMfX3SUTpzQFFG7uuLuXECCaCq7icQc8VUfu920QYIv2RQ1uqu/E7XnNJLrRvzl4WU69j9/JXoIZMkmNBkjw/QNKKnFlyDJE4HkSMgF5h5WcBjdWBdcDeQ0WAiHPphdCCwgxKBWsCylXanpmjADRgjlDn0pBV1L/NgiwxVwu6ZvKVCIgAqwEbI3inM14LazUfOmrZJEhy0qSoXdgYsLJJpIfJlRykJLjk5AMzkcIkI8eojXnEqucAbZq37oE+CYzIwSkhLyGpgbaE0HZJe/A2/PcriwarI/JLJl+8R1osTh3JFmXAMlL+uHQkCntLbabpAIxFGHoHcTxoYVGUz0Jtp/fO7SwaSFOlcTuXlqcAbaayyVjrzKVCIgAKwFbozj5CLmBIQnpte5d+b7onTlEgAQlx1g1snBQX9x555qwbQJs1b51CZDMK3hRJsFxY//KMYsZU2o0wE2YyeM54roESIq+eOMETj4kai+VnHdmjgDR+EjM7s+92bCR4ajEjNuCAFvN5VJsVa4CARFgBVhrFkXj8umciOkjdVSNxHPEHAFiZiULjM+zyLUwJLYuFRYdn3F/kybQ1u0r7XOuXFzcOF/DkahG4jliDQGuMkeioxQJEfwZZE3bc2VzoRbE9JGjtFRy54g5AiTdGcm2vRBC8dTCinD2+nEou0kT6JLmciFku1VMBNhuvKP5ktgsr11MtQTvMhIwe8kRINcexawtLNoxIHuoPkxNv+2TO6cymyTA1u2bwnXs92i+ZGPhtfiSd0dtuoYACbgn8L5U+J4xtfvNj79TsPQ9Y+VY9Mnl6dcOst3gbVoq9ClqcDkCxGrBHE+CgxIabDR1DtWbM9dukgCXNJdLx2anyokA2w131CYwZ562onrMTMSUTREgHn84LiQhdyVnj2SeKZFcTslNEmDr9pX0eahMLrMK5rt4s8XQ8zkNoYYACWmouTaLtGckcPbCGRpnmZuUaM2ovXkid7tGjgBJO8ctEkk49/PXgU31KXeF0iYJcElzeQqrnfxdBNhu2GOSaRxPcEkvXUy5GTyaTHMaIMmPMXslIa1Zuk6npLeYS73TBM9skgBbt6+kz0Nlch6PNZlViL2MpsEaAqRdxI76m9TH+gNZQBpeomfrOnikZ6N3LGeCxOWVChcFR1NyjgDREr0GzK0L1yyshEB9NhAxF+omCXBJc7kQtt0qJgJsN965vJA36+8BnGoFgb6kuIrmtxwBRq2FrB3EXZVogJfqPe7ivLh7f5VNrp05L9CxRbt1+6awHfsdd33OXT3uNcmpCUPhvj4vtQRIGMW9CjsRc2zWptsrrMZiXlo2cwSll+QcJUSDUI0oOQKMVhM0WX+7w1h78Z5l4xYFL9sPDjwYU6FNJRNf0lwuHdudKicCbDvc7OS53y0JpEbKsaGrhlK53N1r/JYjQGKyCHPwMvbRp3I4veBCz2KP44DPXznmjEF5PFy9jMWFtW7fuiP8zHDND3k5ifuaulkjd/cjbaklQOYGpvJo2oz9IkECmpX/pvH6xdy4acndbILH7FUmKiL8AU9afyVYeiRHgMTKkgwgCcHz3CYxdJtDKkfcIxsVymP+9+FHYw47aPf+zkXqIVvSUCL5pc3lTc+Dxb9PBNh2CKPJhNq55w237pwpFGcG8jimlGkQqL+aJ0eAmH64qw0X8CQQImeIQ/cOsmDgLo+miQmUhQPtNAn3GPr4Q48aruq816dOw3kBrTEnrdu37gijuZOBx38rkBHmzRgOkOrCFImnIgsvV//4FHhjBIhmAhEkSZfpcqMB6caGLrdlTuAt6TdXECfhA8yFbUg0T1IHWhfjngu1gbjQ6NCIcWYBG+ZbkhwBQpTMPS9jmzHmFtmV+C4YLzxG8YD1Hs3c7+jjMv27yWjDOaMXHF2G7mJc2lzexjxY9DtFgG2Hjw/mCxnHBjQodqx87Cx6aFUsvOxI8XpDXtDvRP1lokOmyeg9x/OYw1igyOIBYZG6CS853pcWXZwbWHQg5OjVx06cy0whPMp5rRVtyJ8BsWOmvQRMQ4wsxGTySCay1u1bd5RzsV54IkICOCZhJkVToJ+kU0v3NkJ+LNg+UTSLKYtqTtio+AtbCYTHjIfjDfFvYMqdfxAw3p6c7RKoT6YU6veyShB9DU5cNcQGIF74C1mzieJv5hmhCCS/RvNKbaS9aKdpblPvkJUibgooi3fsk/r5xBrGOR/xmTilEKaBcPbK+SGZcLy3NbhxNRnWDjyr/c0QfHeQs18XOUIgeQThJRwl0G+fn3Vpc7lmjPd8WRFg+yHmWiM+vppbBbh+hrMTdq/+4xsyceF9CJlyLlMqXNuDhx0xgGgUOBAMzY/oSMCO2ueLzNXp77Vr3b5SDIbKHbrXsMZuE4/PskEgbyXaB8SVhIBxfzuEf44x8+ZBNiJocJCeD22Y6g8ZUri0tuYOyKl35n7H5MnGLZdQfeh9YMGmC23We7hCYPGGCN7BHGbTxhiUCikDOc9mDHKevOk9kFvcOMRLhWOdmMB9SralzeVSDHeinAhw3wwzgcCYHH3OxqGW8EGS1QUtMXqCjpkaOcPjyqWSOnDW4NYDnweTHbY3g/r2RQJkcWbxGjKT8my82LVl+zYxypiU0eZYUKcE7QfyIvYyeoKi0fh0Z/5daOk+NIZbD/C4BDu0b59IIdcGtFI2Ipz7lWT8mepHye+0Ee0eb9MxwQmL+Yt5EhKJnqBjpkY2HsxlzKhjQp9pC2eHaHoIGiobi5yXao4AIWXGaGiDGgmQOpY2l0vGdSfKiAD33TCDPR5tV+xNkJiKMMnwUeIcgzkMt292s0nuFu52m7rqhjo4OzqgN3dSB2TFzhgNjw+dHXzM7Uh9mC45e0STwLRHPCEESdZ/vBLjRaPs0Am6RitIZ14E7n+3X+w4y/xBgLtl+zY10rjvgyfaMiZIFkqIh3ATFnXMoizWiYCi1+NYyEB0kvJmQcYNL0XGExPrMXtNhHEAYzZKzBfMrq0FLYpxx8xJqjTmGWd8jD+aHlovt1L4tkUP2anwEhxort9fhYTjGHlu0TxJToBpnbM7NgmY56Ng2iStHNhBVsx/sGZzkbuRhY0GxwsX63HG/MzRBH2BTH1wfqpriXO59TyZXX0iwNkNiRokBISAEBACLRAQAbZAWXUIASEgBITA7BAQAc5uSNQgISAEhIAQaIGACLAFyqpDCAgBISAEZoeACHB2Q6IGCQEhIASEQAsERIAtUFYdQkAICAEhMDsERICzGxI1SAgIASEgBFogIAJsgbLqEAJCQAgIgdkhIAKc3ZCoQUJACAgBIdACARFgC5RVhxAQAkJACMwOARHg7IZEDRICQkAICIEWCIgAW6CsOoSAEBACQmB2CIgAZzckapAQEAJCQAi0QEAE2AJl1SEEhIAQEAKzQ0AEOLshUYOEgBAQAkKgBQIiwBYoqw4hIASEgBCYHQIiwNkNiRokBISAEBACLRAQAbZAWXUIASEgBITA7BAQAc5uSNQgISAEhIAQaIGACLAFyqpDCAgBISAEZoeACHB2Q6IGCQEhIASEQAsERIAtUFYdQkAICAEhMDsERICzGxI1SAgIASEgBFogIAJsgbLqEAJCQAgIgdkh8G9QsduB9EnTgAAAAABJRU5ErkJggg=="/></switch></g></g></g><g data-cell-id="A18w2Y2_AVEIFkgUy5Lv-35"><g><path d="M 419 509 L 419 489 L 419 493.37" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 419 488.12 L 422.5 495.12 L 419 493.37 L 415.5 495.12 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="A18w2Y2_AVEIFkgUy5Lv-11"><g><ellipse cx="419" cy="523" rx="14" ry="14" fill="#e1d5e7" stroke="#000000" pointer-events="all"/></g></g><g data-cell-id="A18w2Y2_AVEIFkgUy5Lv-34"><g><path d="M 245 510 L 245 494.37" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 245 489.12 L 248.5 496.12 L 245 494.37 L 241.5 496.12 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="A18w2Y2_AVEIFkgUy5Lv-15"><g><ellipse cx="245" cy="524" rx="14" ry="14" fill="#e1d5e7" stroke="#000000" pointer-events="all"/></g></g><g data-cell-id="A18w2Y2_AVEIFkgUy5Lv-16"><g><rect x="191" y="538" width="108" height="20" fill="none" stroke="none" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 112px; height: 1px; padding-top: 548px; margin-left: 189px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">auth-db-data</div></div></div></foreignObject><image x="189" y="541.5" width="112" height="17" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="YJRAzF6yD4Hh-bAvO1PB-2"><g><path d="M 420.06 364 L 420.06 384.53 L 418.53 384.53 L 418.51 398.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 418.5 403.88 L 415.01 396.88 L 418.51 398.63 L 422.01 396.89 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 385px; margin-left: 419px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 9px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">JDBC</div></div></div></foreignObject><image x="407" y="380" width="24" height="13.25" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="YJRAzF6yD4Hh-bAvO1PB-1"><g><rect x="355" y="324" width="130" height="40" rx="6" ry="6" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 128px; height: 1px; padding-top: 344px; margin-left: 356px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Data Service</div></div></div></foreignObject><image x="356" y="337.5" width="128" height="17" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="V1Wl26Vbpgnno5Lb-wtg-27"><g><rect x="692.5" y="291" width="85" height="17" fill="rgb(255, 255, 255)" stroke="none" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 89px; height: 1px; padding-top: 299px; margin-left: 691px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">search-db</div></div></div></foreignObject><image x="691" y="292.5" width="89" height="17" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="OiuNRKl362wFz-YGv0-T-6"><g><path d="M 130 248.06 L 154.06 248.06 L 171.63 248.02" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 176.88 248 L 169.89 251.52 L 171.63 248.02 L 169.87 244.52 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="OiuNRKl362wFz-YGv0-T-7"><g><ellipse cx="116" cy="248" rx="14" ry="14" fill="#e1d5e7" stroke="#000000" pointer-events="all"/></g></g><g data-cell-id="OiuNRKl362wFz-YGv0-T-8"><g><rect x="63" y="262" width="108" height="20" fill="none" stroke="none" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 112px; height: 1px; padding-top: 272px; margin-left: 61px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">broker-service-data</div></div></div></foreignObject><image x="61" y="265.5" width="112" height="17" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="iy0HhJzZLXsiPmpU2ukH-7"><g><path d="M 530 437 L 449.87 437" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 444.62 437 L 451.62 433.5 L 449.87 437 L 451.62 440.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="iy0HhJzZLXsiPmpU2ukH-4"><g><rect x="530" y="417" width="130" height="40" rx="6" ry="6" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 128px; height: 1px; padding-top: 437px; margin-left: 531px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Data DB Sidecar</div></div></div></foreignObject><image x="531" y="430.5" width="128" height="17" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="ZFea1dL5_0zV0EoV6Noq-2"><g><ellipse cx="332" cy="414.5" rx="7.5" ry="7.5" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><path d="M 332 422 L 332 447 M 332 427 L 317 427 M 332 427 L 347 427 M 332 447 L 317 467 M 332 447 L 347 467" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 474px; margin-left: 332px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;">Researcher</div></div></div></foreignObject><image x="301" y="474.5" width="62" height="17" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="ZFea1dL5_0zV0EoV6Noq-3"><g><path d="M 353.37 437 L 387.13 437" fill="none" stroke="#000000" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/><path d="M 348.12 437 L 355.12 433.5 L 353.37 437 L 355.12 440.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 392.38 437 L 385.38 440.5 L 387.13 437 L 385.38 433.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="iy0HhJzZLXsiPmpU2ukH-8"><g><path d="M 666.37 152 L 780.06 152.06 L 780.06 245 C 783.96 245 783.96 251 780.06 251 L 780.06 251 L 780.06 341 C 783.96 341 783.96 347 780.06 347 L 780.06 347 L 780.06 437 L 666.37 437" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 661.12 152 L 668.12 148.5 L 666.37 152 L 668.12 155.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 661.12 437 L 668.12 433.5 L 666.37 437 L 668.12 440.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 174px; margin-left: 780px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">S3</div></div></div></foreignObject><image x="773.5" y="168" width="13" height="15.75" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="ZFea1dL5_0zV0EoV6Noq-4"><g><rect x="701" y="492" width="30" height="16" fill="#e1d5e7" stroke="rgb(0, 0, 0)" pointer-events="all"/></g></g><g data-cell-id="ZFea1dL5_0zV0EoV6Noq-5"><g><rect x="738.5" y="492" width="92.5" height="16" fill="none" stroke="none" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 91px; height: 1px; padding-top: 500px; margin-left: 740px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Docker volumes</div></div></div></foreignObject><image x="740" y="493.5" width="91" height="17" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAWwAAABECAYAAAClFw9WAAAAAXNSR0IArs4c6QAAGLhJREFUeF7t3QPUND2yB/Daa9u2bdu27XvPtW3btm3bNvbats357emcW1tfejr9zDvzPbNv6pw9+73PJJ10Jfmn6l+V9H1iytTA1MDUwNTAVWjgPlfRy9nJqYGpgamBqYGYgD0nwdTA1MDUwJVoYAL2lQzU7ObUwNTA1MAE7DkHpgamBqYGrkQDE7CvZKBmN6cGpgamBiZgzzkwNTA1MDVwJRqYgH0lAzW7OTUwNTA1MAF7zoGpgamBqYEr0cAE7PMP1AdHxHulZr4lIl7m/M3OFm6hBn44Ip479etdIuKjb2E/Z5duqQYmYJ9/YCZgn1/H19LCBOxrGalb2s8K2I8QEX+7o6//GRH/GhF/HRF/HBG/FhE/HxHfGxG/uuM5D8hFJ2A/II/uvnebgL1PX7N00cCpgH1Mob8dEZ8XEZ++APrdqvwJ2HfryN/zvSdgz7lwkgbOCditY/8YER8RER954HJZ5HebTMC+20Z8/X0nYM+5cJIGRgD7xyLiviutPGxEPGJEPFJEPNUBmB/ySG9+7kCXvEJE/MFJPb6+yhOwr2/MztXjCdjn0uxd8twRwH6biPjkAX08aEQ8Y0S8aES8ZUQ8dqfOX0TECx7ZAAaauboiE7CvbsjO1uEJ2GdT7d3x4DsJ2FljwPt1I+LjIuLhiir/NCKeOSL8/90gE7DvhlEee8cJ2GN6mqVWNHAuwG7NPXFEfNVieecu/MBiaf/vXTAyE7DvgkEefMUJ2IOKmsX6Gjg3YGv1USLiJyPiCUsXXj8ivnDHwDxQRLzwQrk87yH75DGWZ7Pm/2bJRMGTf19EfHNE/OWOZ9eiTxQRLx8RLx4RNp1Hi4iHWFIeZb/86OHvXxQRvzjQximA/RkR8Wapjf85pEu+ekR89Ua70jMdztH/Z4iIR13iDALAf3XwfrzDdy16+s2Bd2hFfnrxjtq/UWDSOMlLHMbhbSPiWZe2jFf+fUcz8eRLimiu82rL5r/nOcqKm3xdqSTeciztVGzmpZb59mzLPHvkiPjvZZ6h9sR2pK9+W0T8+2CnRgH7CSLid8szHzci/miwHWujerDW3+916r9YRHxH+vu3RsRLp38/zSFl900XA8szrAPz6Dci4jsj4tNWvOUHOVCfxuxVI+KZDuUefdGf+fczEfE1EfFlEWFO7xXP1m/z20Ekz4Yz/7WseynG37+MjbV6E3nMiHiViHiew7x76qUN88K8/qfDuvyTZY7Cm69f0ppv0s6uOpcAbB0y6AbpwVLvgMaTDQ6YRfchS2Bz5AX/eeHdPzQi/mGkwlLGoH/gApIPPFDPYsXX//6RsjcF7PeOiA8qz32LiADia2IxvWNEvOuBjnr4gf5bLDYeJzFN8i2pgGOxWBDvdljIH96pfFPA9qi6OfDUAMBe+dKIeM1UyXNtKj0xP8Vs3n0BgJG2gKgx/syI2PIYbyNgP+cyhu1df/Bg9Dx/xP0+buK93mP57zVdWGuvFxFfmwpY718xsF5hAsPiz0YUvZRhsOjXkwzW+aEDwL7zYjSOVJFAAWtsUiMY4Jmy377gsJG90068GenP/ZW5FGBrVD72m5cesmKA3pron5RAR3hvIr8UES85CEas6u/ueAJb7Tpo5D1+fKXgTQDbAjABsgBVG9CasAB5Fs+x1eHO7yxGFssvbNRllb9IKuO/bYjeneVR5RTAtvF8THogYODp/MuO95O15N0eJtV5u4MH8ImdZ9jggM4L7Xh+LspafIOI+I8j9W8jYIsn2cSatA3toxagG1GHd7Z5q/u0B2sc5Sl7bER4xTZQ3ssxAZ6SHxgte4Xl/UaLcXKsLqv6ew6bzVPubWApz1vl/f/5DetvVrskYD/+4ornXetzI+KNj/TSgrVws3DHvmRxx/5wOWlpIT97RLz2Ys3n8r91cImffmOhowy49o9V2uL22lBYUXZRbinX//lKOaCFeqhurGJ7AVuWjftGUD1NPj4i3uGInh56sSC4+llQNminn1hceQHgp1hoApRPHv+/WxYOfa2JDSG7yy97oFjeenFNWx26sIDRMhZio0w2J2MpYCyMb94IuKhc6VFRnmXexMKVvQTEs3Cxgak5lAWFYK6xOlmB5i66AajbVM27LED7tY507jYCtrWRx+iXFwOpGVIA9csjwrwwFuaPd3/S8p6oAdayZ/nNeqF7tBF60tx7rsMaQYU+VKnLmv3sjUH9/KVuLmYc1UN/oIB4SHDGGqrt8H5e42D1f+WRdryz9Z3Fs79poT+sEc/hiduYXnmhe2p5mXBnkUsCthcAHDjBJgCOZduTF1gGO/fRhKf0Nffdgnqfg1LfrzzQzszVXRMTy+Ju8vfLwsPn9eTllkmc884NbG+g9gC2xcOFw5U1QVmYfMfc7eq9KMuVZSWtcYQsIhZlBh3vAIzW2vqGiPDuTbTxYcs/PmW5yKjxpBaP55xyWIrHI27RBHBkeuPIkN7vpzquaxdvmS/vXx72qYuF6eqFnrAgeUE2rSzHNpXbCNhPVzwr42fDRVeiusyhOh8YE+YC7zULfZirzlrY2IF/FfGJH4kIHmGTRsOsjac1bzPMYmwZewy4ntjwxS4y3uDPWc/+vwrjQqytiXVjrh0DeGVf52DIfU6he4F+jgusvdfuv18asNEb+NUsdit3kVT52ZJdwt2gVGC6JTVYx92y8/aAHl8HqLJw9blGx4T76+h9lsbp5r+NAvbjLYGsbOWzaF9xCaas9UVABxeY5T0TkB57B5MZiGRrntWQ+chc39/1p4nAk4WNu/vYrUG5we/cWIuhiWAPb+jfBp6FBmGB5U0V/1kXoOfxoHJ8RRllt0TMgBEC9Jq4T2fNpb6NgI1vRh1WsVZx+WsiACkOVTFEABYVdiyo67lto/d8mzovsbe5P/iyAWTDgiXMmt8KWPLy0HzWVpNPWoLj9b3e9/AuH5D+uCdmwvvN85838IZbk+cmv18asKuLqs9AOHNo/vYshx36p8oLiTZvZUe0KgaXpZAX6xoHzOXNbiyQrFZTT7d0B7By8AM3iiPNMgLYJharI1MaFjdeec3Ca20ANMDWhEuKl9yazK183dxqlkB+F/oH6Fn0WyT9HIJXRkUAxiY2DFH5LWEdCTg2QdXIJqhgLyDFimwCcIzpaEYG4OAyZ+lt3H6/FsCmc57v1twz13iFWQCXDfyYoFUqoNs4fqVTyXmOnE1mfGwWo+c46jwQc8JV18we1EqmZwX9BR9HhEfsmlzJB3DHu6GS7rhcGrB71iwu9Rs7g545W2l7QHgrMJEfY1F7dhMWOyDLAtANoF28iQHmeo+ITUDAkYfAzTJIdvAsW4CtbelRmRfHPfv3ljehrv7njYnlXwOWx94F954nFx2b0L20yB5gv1InbW5Ed6NlcNbaaAKExSq2pI6/je1NOpWqJ8fVl5U0Knhdlnx28ddA61oAewR06adm4PgbbrdHhWR9oi5tBtmzQ8XhwavwdHMgeK/1Kj5hA8rj0/MiK60o66cmSYzOibOVuzRg99wv1m3lp1htAhRNtoI5PQW91cF9xqs2wcvZCXMUv6Y0KWtjOCWHu/blGGDTv3fL7jc3k8U6kuokSJazU3CNgmI1qHZsAukDa4X12QT/2OPvK2CzUiwEGRznEmCdA40sZWN0LPdZgIsO8kYsJiJ7IUvLKbaom1ikFuseQaHwAJusxTOuBbDFKarX0NNHTQpgPEiLGxH0ZKb/em0CdkYLuqTJTfLxpRjmlFAeVaVmZaK5oK6JbCSe0k2D5iM62F3m0oDN1awHNZD2aIkmBsmizJFkwa1enu+xFxYAFKHOUtPMBCJziteeCTeq7GOAXSc8kDZJfmfw4Q6qfEIqaxE8zmDdXEyABP3SZM0drIDNMsehn1OALr2gjZr0vLLch5oWyVXlRtfgmRRImUBZbOJrKZpr74n7xIE2ATK5v+3v1wLYDouNzEHnBMyVJnLy8xd1js0LOJDpxB7lWQOinicD5VgmU69N+JFTYgWzZZJksW4kQeTNmyEC3G3goxTMOdfCPQIGvQ8YjF7+NNJRgMkFzVIXH0uvWpd7+Ov2bIGGeqAFN42jbsL1y9TLOQBoDbAr2EoZQhmNnJ5s/XdXy9un97EI8snIkTFRBueYP1tmA7WRVqmAvScwM9qXXrnK08ucAcprIhsEVdUEF5mBpf2dZ1PpL0HIXhbBsf738uZ5c4KkWa4FsFnJIx8ykVmTM7KOxT+q/gRnZYw06a1x2FDjFby/Pbn4ni/TKI//mmHTO6ymvo1enO3bFyPQJj96uvWUeX+Pupe2sOsxWB2qrqqsg18vPR3J2qgv19t8cJ85ECUPPEdzt9KLbqL8HmDLLuFG5xxjbdPF1mm53AfPwVnfaVlLf6uALWB5k4MMe/uLw8xZOyxYtEjvkIp0OwcXMj8qyFXnlD7Y3OrJUfXka++R3vF3+d6OL18jYIuJjGTiVMBGXeX02GM6HAFsKYI46zstLOd8mCo/3ztJDe4dBGvl6MbmK1vFhjLijdyRd7g0YFcKwkvUOxJqPqQyN3FTLby6oPHa7j5oUgNadtCaW3qqoitgc7sE9XLmQ2tDupN0qlGpaXaj9bbKyQWvh4PUqYDNwq8Hm7aefZPfLR6HaDLnySOwsVQR6c+HMGQb5VzcXL7ylqym3rhs9Zl7LXCcpXdfybVY2LcFsKsXujUOe35HfawlMYifWbejB2DE3KQp9ubjnj5tlr00YNcUOknv9frVXkofBVaucevl5NVWt6XexVEB29HrzOVutTHyewXsY3VYdgKOcntHpAa7RuqMlFmjhipg4+ClxV1CKt8vE6bnXQDOzE8eo/RqSp8NPgcqR9+r5zn2rPoJ2P+v0RELuyYOjI7HSDkpo1v3DOHLBSsFROHSMatbm+hWaYjozbPIJQFbMJGLmBPgexYtJclvzmIBChTsEa6xdMAsNWWvUiLnyCleA2yHBFin+GO3szVhgeP6t1L6lP+skqomLeqmd2GM6PbeBOx6QAjHKt6RD1vgnwWH2vUHfmOVr3HSjkTXjJCbUCJyw+thI15UjcVMwN4H2CjML04T09kClvEe2nBkXo+Uwevjwtv/1i6fwnXzTrdy2EfavEeZSwJ2L4DA5al5ywC9Xp7SO6G29cKyAiq3VC+bqkE7PCfL6E5KD7BtJNLVpJnxHvDX+Y4VaUiO425JvaCnl2u+9Yw9v9+bgK2fDiTk8UFf2fSb8KAy5SU1LR+lr+/KeqLrLDaBPWmR6oqD2PyzyHKqi/ZSgN3Lxlq7XrWXantbKBEBxpwkQL888rXj6Hvm8qllGZYC8zy4etGVGz/r9Rintne/+pcEbLxoPhHH+mFZ1sCMPnEpMlUiCAD49kjPTa28YuXI9Mlk3XNAZ6tPFbCdoGMF5/RG72eQszjkkY9l99qpQTMHeBz1P5fc24Bd9VQvD+NhCNw22crZrTfVqee2NcC6R6SMSR1rAvBzXnv7+ymALesJjz8iNT9fnWsE7F4CglS/3lH6Eb2cowwD06aSr+zl0Rn/0dPGw/26FGBX10YH11LH/FYX3p7oc3t5VIPjok3syjJHshJZt2iQLE7+bV0z2srjO/PuylWr3sHWSUfPwo155xzok7qENzt2J0MvTXJtYQ5PiiMF723Alh+cc3ABo4NC9G7hoEMaz4hS8tuxbAf0h3mReeubpLGy5HNa5FqWzShgo1OqISMFrlKFa0NVPY1rBWz4xBvNOe28mXNkjpyyPsxLBljG062PZNyovUsAtotwBNHyDXSCO+4gEHjoSbVYBAdYjntufqtHWv073+Ws3d7R9K17p3N/fbzArW5NDBqrIMsIYCsvW8ZGkTcAOdmspTXQweeZ0Fm357qISR/vbcDWB4da8jWo7S6a6m3g90dy0h32kIXUZG+mELDn2eTTeGse4ShgSzmrbn/vpObaoq+3Kl4rYOt3vfJ0i+a6ERCmSrKE4NNe6xj9mr+qxfjCKtxROTdgu1dA1J6lkwUgA8Y1AfL3LT/u+aSYHc9mkE8tuSCp3q6nCUfDM1/ssA3QPXYRfeuagwI5DbCXuTAK2J5Zj2H7m+P17pxek3oHgqPtPmm0J7GfSyc31Vj535rrfRsAu6aGOmHoxF1d2KMLpm66MnXw5PQ4IjVXmLWP3+zVHwVs6xJg502gF+/p9c/ctXbq11KukRLxfvVqVeMDV9aMvZ5O8MlOYLb5XQ+nuQ5VOwLbsEde/d4UPR4Rz6jJyJ0qI/Pr/sqcC7BNFgtBTnG9rNyuw9LdAkSBOHxiE0BKoTXzo760d3IPbr74CScuW6AXua2HMjwPAOSjxj3FOpWIxsg6FEGux+H3ALZ26u15/nbshrp6Ab3ye9LtKgCiFVxF2/NmbgNgoz4sjgZIKC0LjpXbrkh1Y5rb5kayCcRKnHzLBylcRmbRbtXnDUmBpK8mjvnXS/Dbb6OArXy9T8cVuryJY31i7Zt/+R6e1va1ArYxdb92jgnQjbU2YpSgFek9016VB68nVd0fwusaOTxEv/XsiHoYgTt+x86dBmynu1iJrIFe2oudn2s3crkScEalZCuZ++oIa+X32qS0Ofg6i3StLFsX+vRcSG6tZPheANLHP1nmmb5Yu0dhL2B7B6lB+U5lmxRgXrvyU2ZEPXGIv/cOa5MOf+uCesHOPA9Y8/nSrKzH2wDY+oO2MAbE+BjvnKVB5959VHoHNHgujv2vgQIKSx58/iSbsg7prF0vsAewjUt9h+ZN9N6LQeIaUkDmsJCAvjTHawds/e9l8zgzwbs5dscHQ0fgPq9Tczhf1OX5NmuURtaXjU+e/1agV2wBTZO/wHO2KxtGANuBlUpP5AkDYCgEyZ4vCq+TimXN6h25o6DV7Z3tZy2jHlgyLCPvgHJh8UqzsZCyODqaL93vTXaujF21fvJJTrSAJ24a8Hk/FEi1YHDsFmrv+PNewNY/4GyzylYB/Tl51dtAjIFFWj8RxjJxFN9mIhgqIGdh6ysXMFuG2uUysg7XrLjbAtj1jmTzgLHQZE+ATh1zyHyqFwIJcApwsegEOOnZHLBZCKRnysJzAHy+jKvOtT2AzSIWZMwGi+dJBeUBmJvoAXOWJ+pIuP6Yp6xD8z6P79qFTrc5rS/rr3cNg7ta3AUDvBlxNkyWLQvaFar1Y8vmCUOwl7bZ+yAJLxPtydtHcQlkmytiRvQJc6Qe1gujtH+W4+ojgD1qpayVM4Gcz2fx3SRdrn4JYk9/ZKLgrrfoF8+0yA18Bfyt9mwgQPxOfoRXmz2rz61w9VNWrX+uObXT5wDaVt/z7w4moQGOuXG3BbB7X5Np72Kju8mHiAWgWUb5m5Wj+hOgcolY7+O++Rl7AFu9vXNfP7j35n09Sbi2iV0LYKPAnNlAtd5EUKpSfY9l2tTbB/e2w3BjHFZadO9zVsufE7DtRtwRfOoahTH6IgARH47IHxEcJpeyF2Q8Vh9P5mY3u+3IJ+655jIRjrlNN7GwWx/rR29teDh3O35PRLhZee76Hf1qNWtDENhi2IqM3xbA9u4sq95nvI5ROltzh6XkODTPLrvHx+qxvuVgj2QE7AVs6xNo60+1tGuf0IzuUWn3WOPWpag2WQuCXQtgt/dAZwDWfNPfsfFhMMIhn83bOoruOVgAVznvOUDHI+XRuJtmNFi9NRe7v98JwAYiXBNUB0oAf8daE5Dbk4a39QLceWDFZecCojHaIREBJy4/15+VDEhPaRv/buDsyFwfi7elAHJ1LDxWzMjl5qcAtnbpM2fZ4LFRJseCrwJpLEUuvsMhnsMCN7FMWu60FEI0gGj4aHDlNgG2q3Lrl4q2jqJvzbH2Owue/lAfglb052gyl9uhCBu0jxSYZ3vuuNkL2K0/+Gg8vcwXXGnbjIG0+WEM0YT5Otd6UG3tPp5rA2w6YUxJXLA+HcazPoyRTY0OUB8+N8bSBaR7T67CGhgDa1Ao8MD6QTkxamTw0L0v6/CsrYt6lfPoXNtVrgL2rsqz8NTA1MDUwNTA5TQwAftyup4tTQ1MDUwNnKSBCdgnqW9WnhqYGpgauJwGJmBfTtezpamBqYGpgZM0MAH7JPXNylMDUwNTA5fTwATsy+l6tjQ1MDUwNXCSBiZgn6S+WXlqYGpgauByGpiAfTldz5amBqYGpgZO0sAE7JPUNytPDUwNTA1cTgMTsC+n69nS1MDUwNTASRqYgH2S+mblqYGpgamBy2lgAvbldD1bmhqYGpgaOEkDE7BPUt+sPDUwNTA1cDkNTMC+nK5nS1MDUwNTAydpYAL2SeqblacGpgamBi6ngQnYl9P1bGlqYGpgauAkDUzAPkl9s/LUwNTA1MDlNDAB+3K6ni1NDUwNTA2cpIEJ2Cepb1aeGpgamBq4nAYmYF9O17OlqYGpgamBkzQwAfsk9c3KUwNTA1MDl9PABOzL6Xq2NDUwNTA1cJIGJmCfpL5ZeWpgamBq4HIamIB9OV3PlqYGpgamBk7SwP8BHlHUkOmuIvUAAAAASUVORK5CYII="/></switch></g></g></g><g data-cell-id="ZFea1dL5_0zV0EoV6Noq-6"><g><rect x="701" y="512" width="30" height="16" fill="#e6e6e6" stroke="rgb(0, 0, 0)" pointer-events="all"/></g></g><g data-cell-id="ZFea1dL5_0zV0EoV6Noq-7"><g><rect x="738.5" y="512" width="132.5" height="16" fill="none" stroke="none" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 131px; height: 1px; padding-top: 520px; margin-left: 740px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Ext. maintained images</div></div></div></foreignObject><image x="740" y="513.5" width="131" height="17" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="f61RwCrreTIYbJ5Vt7fi-7"><g><path d="M 65 317.63 L 65 294.06 L 250 294" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 65 322.88 L 61.5 315.88 L 65 317.63 L 68.5 315.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="f61RwCrreTIYbJ5Vt7fi-3"><g><rect x="0" y="324" width="130" height="40" rx="6" ry="6" fill="#e6e6e6" stroke="#000000" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 128px; height: 1px; padding-top: 344px; margin-left: 1px;"><div data-drawio-colors="color: #000000; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Identity Service<div>(OpenLDAP)</div></div></div></div></foreignObject><image x="1" y="330" width="128" height="32" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="f61RwCrreTIYbJ5Vt7fi-9"><g><path d="M 64 386 L 64 370.37" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 64 365.12 L 67.5 372.12 L 64 370.37 L 60.5 372.12 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="f61RwCrreTIYbJ5Vt7fi-10"><g><ellipse cx="64" cy="400" rx="14" ry="14" fill="#e1d5e7" stroke="#000000" pointer-events="all"/></g></g><g data-cell-id="f61RwCrreTIYbJ5Vt7fi-11"><g><rect x="10" y="415" width="108" height="20" fill="none" stroke="none" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 112px; height: 1px; padding-top: 425px; margin-left: 8px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">identity-service-data</div></div></div></foreignObject><image x="8" y="418.5" width="112" height="17" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAcAAAABECAYAAAAWc+UJAAAAAXNSR0IArs4c6QAAHHBJREFUeF7tnQXULUlxxwuCBIfgEiQhuLs7Edzd3YMTQnDXYMECBEhwdxLc3d0J7hI86PzYqaW2aJ07M+/e76s65519+25Pd0+1/MvnUBIUHAgOBAeCA8GBfciBQ+3Dd45XDg4EB4IDwYHggAQAxiYIDgQHggPBgX3JgQDAfbns8dLBgeBAcCA4EAAYeyA4EBwIDgQH9iUHAgD35bLHSwcHggPBgeBAAGDsgeBAcCA4EBzYlxwIANyXyx4vHRwIDgQHggMBgLEHggPBgeBAcGBfcmAKAD5IRO5iuPVSEbncQtz7nev33CLyroXG2ivdrrk+e4Vn8R7TOMBZPKd59HYi8shpXcVTjRy4l4jc07T97+FO/PvGZ6OZ40AA4N7bEgGAe29Nt/WNAgDXX5kAwBl5HgA4IzO3pKsAwC1ZiH0wjQDA9Rc5AHBGngcAzsjMhbpijf5FRP5MRH7YYGLqBcDe/hd6zeh2BzkQALj+om0zAJ5ERK4/suRDIvKS9dnTN+IUAPxzEeGP0q9E5Kd9wza3Dh+gyGlE5OMjx/5XRE5a4V7v+vT237x40XDPc+DIInIY85Y/F5Ff7vm3PrAvuM0AeAsR+beRPU8XkesdWFbVR58CgPVe52sRAChyQxF5cgcA9nJ/6f575xPtgwPBgTwHthkA/1NErhUAON/2DQAUeYqI3GBBAFy6//l2Q/QUHAgObDMAfl5E/ioAcL5NGgAo8gkROfWCALh0//PthugpOBAc2FYAPI6IfMssT5hAZ9ir+x0Ajy4i3xc5+LNVLT7AHrYv3X/PXKJtcCA4UOfAtgLgZV3Qy54FwN4oQ13Sw4rI5UXkCiJyZhE5nogcYYxs/IyIvGEI8HiaiHzB7IFNABDn/N+KyN+JyHlF5LgicqwhovLXIvIdEfmaiLxpSOR99dDuHfV9d3CLBwyO/rua9ncWkYea/8cEgMnyIiLyN0PUJiDzCxH53lAwgMgoElfZHD/LjHmxYb6v7ZjPowYe3ta0r63PlP6/6KJPCXw64cjHjqn+oek/icgDzUNEth5/5FFvX7X2RxKRS4374PQicmIROcow/uHHwK3vigh7753DnqSgw4drHWZ+Z40Zh712piEQ4Ngi8hci8mMRYQxMQ6zpK0Tksx1jvE9Ezmrac27YQxDJz7cRkbOPYx16PFcUqbiaeQYN/7QdY9qmjHVG8w/PdX1vEgV6DBG5jIj8g4iwNmgQ8PH/ROSrw7+/exj7xeN5+e2E+S91/idMpfjIKUTk6iMf/nLcO/8/3k8fGHnwovHeoqNNAJDzAL/Zp6cb7qGTjefhcCPfEbY5A28f7q5nisi3Ky97PxG5WwdDuP9LkaFzz686tSlBMLULNjXoOYbL56kNB/E3IvKIEWD4+1QAvOoQncbinLzKgYMavFVE7igi72loD/gBgkr3GSszcAHdd6ySQ8pCiTAVcEkBwJ6mANTSAMg7fn0EDp3v1KofHxxBQvt5/HDQiB6bk1gL5nd3ETlaR8cIYczl043PEHF7+0GYQQhqGYeLnEABLg0EsBq9bRTetB2CHMIaIMc59ARAnmgAzZe7HwBAgLCHuJg9HwD5V5pOpgAggjDATWoPgFejT4nITQeB8i21hub3Jc9/xzSKTRHC7j0ISXdwkbSph+ABwSXvH+8aQFCppRIM54F9yt2FYNZCgDARnf9cEE7nAsCl5ld9zzUA8Dwi8rpR26tOaGzwguHAXmW4KNA0LJjUSqHR9rEicrPWgUw7NEM0Ny6oErFhH2Ya8Pc7jc9pBFTL8Gywc4kIgGBpGwEQgH22k/4/4rSDlndOXaqU0moRPFr6pw2S/3NE5IqtD7h2Pxnmc4lRKCp1ccxRo2MNewnJGutETeNEa2Q/KPF3NCSAh0vDEwBIysw3RIT5KVE6CyGmhxAe7DNYTU5gNBH66gVALD4vHLWQnrkgCCOYPKHy0Brnv2feubas3fNHa1hrf6Sasf78QdBWqgEg2h2aNHt6CqGJY81KWazmAMAl51d936UBEJMjUqSXOtB8MAMilbKwmD8AymsPF+0px1mjkd3faR01AMSEel331lw2pBEwJhcDDCdh8+Jj2yOa9hw0NLPnFTj3j84cCOB+WUQeMj6Dn47NzeX2g0GjPeqo+V4zkcOHRHc2NxbzU35hV7eHHtMQJi9L8A9Tm1JNQ5/a/0VHQcaOjXkOM00r3WOUerX9Jua53JjexEo79iDmO9aE/YBghcYGIGMSwpxoAQVzNfuQ/6YIUw2gTQ6lJYSCZ4zmO55l7U811splLe15w/TLWn6uwDxMppc0v196MKneajRh6T8DiAhTaFP0h9kSrdoKgR8bzYyt60Q7nrGm00cP+5m9b6kHAHl3LmvOnSXMw5jFMEWzjzEfn2/kGdqipSuNAJp7jzXOfw8Pc20RLBAwLLEf/n24B/9nvKfYY5goWXM0WgQ7rDDcm9YFUwPAxw3BKTd3Y9EPQiJnl/OA8I/AdJbxDsaKYOm/xn/370MeKH+gBw/uq+uYBtyhfr9wH/o80SXnV12rpQEQcLilmwWq+L9mZsaGx7wI+CGJY2KyibYlAAS40FIsAUTkuVmAsL8j0SIdYaJVwmdD1CX/TRHmG/xuSpjNAG/mytzZ3KlkYHxP+Jku7DoFAAHCFPl3agmCqQGgHaenf/YKl7WGOdMP63vr6i77YwO0Ewsa3n/a0VWyKfuHA21Na1zcmENLfiSAnH2AD0YJPtqLxg6IUIJZTgnBibb4gnPjYL7El4Owp4RQhnTtTf36O/sFP5kSY6j/FPMU1ocvjT8i2NAP4A6AYNa3BBC3mnYBPgDQEuCKT9JSDwAC3I9xzyvPcHd44gxiyv1r8wMXKPsPsPC01vlPDN31T4ALYI82rIQgiF8OATdFZxitDexPeID/VKkEgKw5Z84Kd5iwsa7lYhCYF4BHrIYS+wpwVP9zao7+TLQEwaw5vyRjlwRALiEuIyvFIaFpqZzSrrEJlbZdDgCxp6OF2cuF4BZ8FjUHOvNEMyBAQomDCtClKHWQaYc939rmU89ymLHnW1BHY0F6SlEPQOnzSwEg/eO7wuyhhNMcIaKl+gdO94+aZ7n0uAy+WdoInb9dYBAw3myeoW/GSF2wvmtA8L1GSwNYkMA9cRF4gQU/iQ3syU0bQQu/nj0TmGoBxhTx7wQOKHFxorVihsdXniPONYFLWDqU0Djs2pVY6zWUTya0XZ5vBUC0BLQOhEAl5uK1ID8nLkguXc63EnvQ+uD59zXPf4lvLb8hJCHgKyGwIHDUgqMQHHGXIOhYKgEg9wpCphLWIu45zm2JsIohbGPBU6Iv7qocTQHANeeXnPeSAIg6jBSghBRBVCQmjxpxqdLOllzjmRwAYjrF9KTEhczlhcmzhYjCepZpiJRFZGLqYk8BIBc7/peWixaN0WqBmCIYP0XbBoCsC4KG9csiTaJp18j7CzDvYd6Zk/DBWh8uvmdvciuNpz4vwI8L4I0JAcoWDqAvLmjAsyZo6bhPHMDgJmYSr3JmTjs/fOHel0mEHhpejQBke2Eh5BGh2kJoigCtUg7gWwHwxoOg9CTTH4Ix5zOnhdg54r7AiqOU8j2vef5b+FdqY5PFace95d02ueexPHnBvASAuJAuNCoGKAfcPVagKs3TmyZZa+7fHE0BwDXnl5z3kgCIz4XLUYmLApBoJfwC+E0s5QDw9aMpSdu2apraHo0MbcEGDuQk8xQAcsC1XFnt/R4+RmRpO8xg3iyqv20bADIvzFJo1kpo2i0OdrQXBCClmj+nxsfU755fjKk+5Sn9+WfQNBCOrPmKeodW0KuNAwjZwCeEJoQtgkw8pQAQ0xTm2hp5jZv2gFpN0/DzQ3Cl/iyCj6dWAEQrRztXQghoDVTDNEjQBz5V3BLwCa0Gv5XSmue/xvfS75h1fTQu31LF1N1Cfm14puYDtP1y3+fM7X58hDTWSYn1txYF334KAPo+lpxfkr9LAqCtMMLgKSd6adHxsfiorxQAoo38aPC/4DRWatVK7PgesDFVWPOBtk0BIGa2lrB2+sD8YfMGcUTbXC87p20EQJ/wygWOWQUTV4682ZDLDG2S4I05CT+VjyjlIBNcMAcRsWo/yMxlQj5rLV/KX0JYJshLVSLQBU3QkwdALBIIaa3F59GWyLFTajHVes2xJKC1ACDnk0AdG2w25Xzm1m/t87/JPuK9uWcsEfCGUNVK7B32nFIPALaOQTsEVGvZIY6CoK4czQGAS84v2fdSAIiPg0NqfR0ESxA00UrnT+T+pAAQB7EPJ0fTKEXXpebg8/ty5jMPgEik1vdYez9bMZ22OKmR1lO0jQCItvwVdwjhXSovTd+JCFlSRZRKPtYa/0q/s58RvPAdKQFSmJnQvK0Pcso4PgAKocdHzLX0y6VFGoQSOXGYgzx5AERzRJhoJZ8v2PK8N9GRGvQfmQFbABAABogtkVzv/631nXy7tc//1HnynE9iRxC0fraWvr22uxQAoplaSwP3uUZ8pua5NgD2zi/J26UAkEuBS9IS0Ww+Qbe04FQa8VFRKQD0Ggl9IlG3+Bfs+IT5cxEp5S43D4AEtWitzpYNjOmHMHWlXQNA5u0DbWqmRnxq1nzCJe7zH1t419KGqMrXOOFLn6PKECZbhBvMcj2SN30QvWyLDmBOtP68lvnRhiAWa0am6kYqh9QDIBK5dSvUxkMzh/f2nFMcIueH9xo0nzdC20CDS1ELAHLuvYmPFJRcn7V38r+vff5752fbe39myfqTGwdrxo3Mjz0ASMQ5eYQIJSgJaHRaGcmPR7CNDVpaAwCXnF+Sn0sBYMrWjZ8rVfkkt9AsDqZNSykAxIGMz29uyi24B8BULl9pLnsBALlEAT27f7RKiX93EsUpNaZUSqBHY+kJjMGhn/KdcenilytVGiFoBRDmAuGCbknGRxNa4htnhKZbQFReeQDs8Z1pH1RQwZqiVIo6Jq0CcFYqBWjRpgUAfTAcz2G2bA0aqp3rNc//pvvTu1kQwghS6SGif0nrUWoBQMyZWBhsYFPPmLRdEgDXmF/yfZcCwJQvhouQqgKtxCGxjm6eSwGgN0u19t/SDnOfj+wMADyIcwgzFzRMRLolGMiT15pKJdS8hFxbI/KicrlTaD9EdRJh60PHU/2iFRFlhymH0PQU+bSE2vxafydnzwaJ6HMeAOElebQ95AUucvl8MQX64y4g8tXmQuZ8kzp+CwDi+sD/r0RdXBtE1PMuqbZrnv9N9yeCjg0Yw1JBIYYeIiDIWqpKAEj+H3NuST2rzWEJAFxzfsn3WwoAfbAAg9equPgJcki8GTPVh/ep1Ray5/eUqSYA8CAO+pQDnOSYy+yasb8whWPOhmpFtDe9YFJrS9AIEiY+AwC7dvmSAkCkZap2JtUtrtyzgRrb5nxzHgDxY9ocspbuCbIgwtn640lB0AR67YNiDqRYKFGvFleGF0LtmFMAkD3QIpC0vBtt1jz/m+5PzO9UHVJq0d48H3zuXKkP76qgL9aTlC+sHhQ7YG9wZv069/rYpvgA15zfqgCYCsHGN0NeVSvhHPbmrRQAUmKMygVKmFbQ3FrDfVvno+0CAA/iBDmaRKRZM+M1XDUen5hOakspD2nTC6a2lswZUy1+EHy+RN+mamriG0SI8ykD3v/CfmZfL0VzACBze5kzLROQZOvZ0sbnmD3SmdpS79gCgCkTKGBcAtYefq55/jfdn349MU9bK0rLe/vqWjkAxMdHfIEVfEhlAIApbFCjpQFw7fmtCoDkDVGJwhLOag5iK6X8iCkAxExDUrUl/Ie58met4+faBQD+kTP+MLK+NneTcl32Sw+9e2DTtao9j5BFvidmRe8fSV1OvorHlCCG2pzs73MBoI8mxhVhi3gjBGBKJh9RqaXOawsApoJUGGeuCkBrn/+e9fNtfa3Slqhc34f3I+YA0JtKUQxQTFrAjzGpP4oPWGluE+ja81sVAMn5oZanNbFiq/e1AEubyUsgtE0BYOoLA4RGbxryHgBYP+o+MZe8PvLbqNWID5fcQE0RIVcOU+hckn99du0tkJKpfGGj63ja7yOfHDwljL19ViJzASDnEZOmDWMnKleT29FCbIBaa5HyFgBMpSkwXs/njUo8W/v896yfb+vNl5Qks8U3Wvr232jMASCfzbKVW7xwWhvLp9DMDYBrz29VAGQwH/reWzg5VTE9BYCALBvJmuJw+i4RGcp7hQZ4yK3kP9qqeWOYWvB5KBG9ZiMMawdw7d8xm+P/s8W+0V5tygqVjPzXL1L+tLnmPhcAMh9yISkZpsQ+RkOHvCZfy+vUPloAEEEIa4z1vZJKYgvKl/jF+bZFA2iL4KGBSmuf/03Wlghin1OJFSL31RE/FoIMd52tjZoDQIQbG9DEl1jsZ5Rq70GqEG4CpbkBcO35rQ6APuIJjQxpsJVIL/BJv7lAGu9cJt/QVtFvHbOlXQDgIbnEp1bQnpT0QPoLd0mt3K8bJj0CLYg47CE+2mwj5vylAUhyAdn8qFph6p7xfds5AdALJJp64QOVMJWhHeaia+0cWwCQ9j4Vg+8c2kIAJR6lXCFYEmzloTXP/ybrmYqOLxVD92ORIuTdSDkAxI9tlYKeikjwnAAZ6x+fGwDXnt/qAIiUZz97RFAKFc1JHK+Rj0jT9jkA9D4OzGwke7aMpX3z0VACJPgeF39ylSoOJAASUWm/WpHi4yZfg2jp34+Jv5VgGC11Be/RojCjqcmtN1eytj9Sv1Pzk5B7hCYqjQDKtvpMS59Ex9nC5KnqRT7ajfQJqvm3fBFD54DPmgtF95ovGqHt5gRAb5Im8o8IUczYtrwbBZOt5F/iWysA+rKGPf4oyhHar6WkPgm25vlv2Ue5NqwBpmhr9qzlWtq+2C++uHsOAL0FDpOmfrO09A4IeeQncgdbwr1hNU/fhz8XFKW33wf07dee3+oAiBTpQ6050LUwckwlSIz+Q7G8QA4AkfZRqa2phJBuDnLLxcRYfKbGLnBOY1kTAJEO4ZkSlxagUopw7QHAKf2nNhJJ53azc1CthG/NbZtcIKVnEQy4HJUAGICw5esjPEMtWSrF2LJ2qchl+vTfRetJT/B5cQgPnJVU7uGcAMg74oNnLZS4TClQQY1QpR73QSsAIiShsdl6vQAtha5LPmHMg0Qy2jXBjIdmbmnN87/p/vVWBvKMCTjy5Rz9OL42p/6eA0ByDOGvUovWjTWAnE32CEFKtuYo/ZQq+Pi9VctxXHt+yXVbKg9QB6OWHMEslpBC+KZXauNTIBnfHQeTFAjC1q25qZRLmCo0y6JTKaL0WSTC8vnEjf3IZAmo1wRALicuCksAC++Vox4AnNJ/atxU3VZthwDCuta+QbbpxcLz3hSGAEaYPA73EnGwkVhtFRr2DD6U1Ceu/BfX6Zu0Ar5vlzO7EmiDFI5v2567knAwNwD6qjwAN2dNXRMIWFx6rRHUrQAIf4i0ZTxLFBYg8ChVko4weUq/IXAo0Q7zHFqUp7XO/6b7FI0bP7LdAwhu7L1c4B6+Wz4nxX2IQGc/EpwDQF90n3mXvjyBVorbgkR9hDES9PEDWioVRuB7qFYwYQ+RDZA792vPL7luSwMgEVosqk98JdiAr7fzXy4MNDcuUUKm1WxGVRHMkrbYcK7clr5cqlQV0aiYGQANpFAuZCRLDj0akK+KQQ1QzGi5Cv9rAiCbEkHArhOaDeYGctSQrOGxrcDSA4BT+s9dAJibU58e6q1fuckFg4mdj9raLw/QHwCIVkoIuAZQoI2gNfKRWhLffdk0wsBJfE8R/TOO/bo97bBCYEZlPC5pfCiAP2NgpvOfk2FO+OZyGv3cAMgcKRKvFyjngfkpMXcEhlbqAUB4gTDn896IGH7hqFXz92OPdwGl4WwOG3PyeaZ+nmuc/1belNr5dAjaYmJEYaDYtUbsUnIQAV2/4wj44VayHxXIaXaYtwFWG/mL0oGGx5nExwugcn8AdigKqmyoX5u7xxbrZnwqC/Ff7nTubyXm6T/sjACKxsv7cMcDrFo0f+35HRAAZFBMngBQKuE4t0m0OLD/hlwtfBobO6o4gRlTiA2DhsW4OVoTAJkDn8kplUtCQ7FfmO8BwCn95/iCvy3lY6iV05qyTqVnkKTJlapVfMn1ARihqdlPVqXaIjwQbFX6SGhpnkjXSOSlTxstAYA+/8rOkX2GaaqVegCQPrmMKYbQ6mPUeeAzJI1Ko1Zz81vj/LfyptQO4Yv1t7mYtX7RqKgbypdOuB+VSsUYptRJtQUQUkCt4/r6tZw3QBVgyxHgThEKpTXnl5zT0hqgDoo0R1CCDctNTYiNjpmEMGwudh8JWjP/aZ+ALge99WOoaKGYQfGF1KrUrw2AmILQKHKfTdkUAHv7z21u/DQcACu1l8yItQO/ye8k/CIp28PW0h++PUx1rRWLkKAJ9iJQw5rQS2NhWXjAKKjVCkIvAYBcoKlkaKR0oitTJt/c+/QCIP2gOcBjznjp+3I6JpYFLBz46FtpyfPfOodaOywO7NGW4upoWgRnkTjvI0G5G7CM5YjoT7S+UgALz/LhAfYxplYl7gbuYOuG0t9SBdzxU6LsIIikyAMgbdac35/MaS0AZGCkPzYmZk4uKFRiLhDMHmhcXDqYMGzQgo966gkZZhG4AAHN842+DcwraEuYRTF14mDHLINU2vpR07UBEN5hOsNvilObKhqYcfGHwDdMcVwmSr0aYG//pYPtvxZP9B5fHzhQhIkS4QtJG2EI/xbSt+4B/BNcsPhk2APkNE4hLnI0XfxpBDSwz9AQ0SYRqKiKRJAD/houjtb0jCUAkPdLpRhNKbQ9BQCVv2gK3AWYgInYRoDCF4umw9nkCyLUq8QCMqWs4VLnf8r+KD2DuwVzO1oxAgiCLuZQzNOsE2ZRTMQaM+Ej5FvSyzBzY7pkDEyegC/mSIQeot3R+tEqU8I/a4N/j7KG7HNcCKRIoDDYSjH6joAxQMo8GYe79rvjM6xnKj97zfkdYi2mAODcGyD62xscYC/hl7QOekCnZE7eG28ebxEcCA7sJAcCAHdy2bZy0j7ReulC0VvJhJhUcCA4sDscCADcnbXa9pn67wMSFYZZMSg4EBwIDmwlBwIAt3JZdm5SPqEesyf5WrUgj5170ZhwcCA4sHc4EAC4d9byQL0JxaDf46JUa/laB2quMW5wIDgQHDiYAwGAsRk24QDFBDBzAoJKhGUTdTslcm+TucSzwYHgQHCgiwMBgF3s2teNCesnz0e/hkCdTMK3bRI+Ic+kAUTk577eKvHywYHd4EAA4G6s0zbMktzN0keGyV2ison9BuA2zDvmEBwIDgQHkhwIAIyN0cqBEgBSOR6/X2sFldYxo11wIDgQHFiMAwGAi7F2z3VMZXeqclCcnGLQFMqlsDJFzakij/kzKDgQHAgO7AwHAgB3ZqliosGB4EBwIDgwJwcCAOfkZvQVHAgOBAeCAzvDgQDAnVmqmGhwIDgQHAgOzMmBAMA5uRl9BQeCA8GB4MDOcCAAcGeWKiYaHAgOBAeCA3NyIABwTm5GX8GB4EBwIDiwMxwIANyZpYqJBgeCA8GB4MCcHAgAnJOb0VdwIDgQHAgO7AwHAgB3ZqliosGB4EBwIDgwJwcCAOfkZvQVHAgOBAeCAzvDgQDAnVmqmGhwIDgQHAgOzMmBAMA5uRl9BQeCA8GB4MDOcCAAcGeWKiYaHAgOBAeCA3NyIABwTm5GX8GB4EBwIDiwMxz4PVuWa66Pfm2cAAAAAElFTkSuQmCC"/></switch></g></g></g><g data-cell-id="f61RwCrreTIYbJ5Vt7fi-12"><g><rect x="701" y="532" width="30" height="16" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/></g></g><g data-cell-id="f61RwCrreTIYbJ5Vt7fi-13"><g><rect x="739.5" y="532" width="111.5" height="16" fill="none" stroke="none" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 109px; height: 1px; padding-top: 540px; margin-left: 742px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Maintained images</div></div></div></foreignObject><image x="742" y="533.5" width="109" height="17" xlink:href="data:image/png;base64,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"/></switch></g></g></g></g></g></g></svg> \ No newline at end of file +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="532px" height="614px" viewBox="-0.5 -0.5 532 614" style="background-color: rgb(255, 255, 255);"><defs/><rect fill="#ffffff" width="100%" height="100%" x="0" y="0"/><g><g data-cell-id="0"><g data-cell-id="1"><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-76"><g><rect x="0" y="91" width="530" height="397" rx="7.94" ry="7.94" fill="none" stroke="rgb(0, 0, 0)" stroke-dasharray="3 3" pointer-events="all"/></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-77"><g><path d="M 336.37 137 L 348 137 L 348 331 L 455 331 L 455 346.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 331.12 137 L 338.12 133.5 L 336.37 137 L 338.12 140.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 455 351.88 L 451.5 344.88 L 455 346.63 L 458.5 344.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-78"><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 296px; margin-left: 411px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">HTTP</div></div></div></foreignObject><image x="396.5" y="290" width="29" height="15.75" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHQAAAA/CAYAAAAxBeyIAAAAAXNSR0IArs4c6QAAA/xJREFUeF7tm78vNEEYx78rEoUG0VGJHxGJSIiIQuFHkKAglCRErVKQUChIUPgDRChPUIqCwu9EQSHRiEgkNKIhUQg5mXvf2/f23tubW7Nr5jbf7dzMPM8z388882uXFY1Go+ATGgUsAg0Ny1hHCDRcPAk0ZDwJlEDDpkDI+sM1lEBDpkDIusMMDTPQ1dVVjI+P213s7OzE3t6eUpeLi4vx8vJi27i6ukJdXZ399/7+Pjo6OpR8yBqPjIxgfX0dv+krMabS0lI8Pj7KwnSU5+fno6CgAKJtY2MjWltb0dPTg9zc3LR2HBlKoJ40T1k5PnhUgaYyLuDOzs46ki65HoGqM3RYCBJo3FFfXx82NzeRl5f3X/TagT49PWF3dzcjWaenp/H8/GzXnZqaQllZmbRtZWUlWlpa8Ju+0mXo/Pw8KioqXOP++vrC6+sr7u/vcXZ2hqOjIyRfuQ8MDGBra8s8oFIaCRXKy8txd3dn/3J+fo6mpiYvJjKu66ev5DXUa9y3t7exafbw8NARfyQSwdDQkOM37RmascIA/BRZ5tdPX6pARawfHx9ob2/H8fGxHXp1dTVubm4IVAZTlJsGVMR0fX2N2tpaR/gie0Ws8YcZ6kLXRKAi1JqaGkdWbmxsYHh4mEBlWWoq0MHBQcdmaHFxEZOTkwSarUDHxsawtrZmhz8zM4O5uTkCzVag4riys7Njh7+ysoKJiQkCzVagyUvB9vY2+vv7CTQbgV5eXqK+vt4OPScnJ3bRUlRUlBlQcZuRuIOSiZCqfGFhAe/v73ZR8uW8F5t+blRkfv305dc5tK2tDScnJ3boqV6epD22yDr9k3ICBbzeFD08PGB0dBQHBwf/MtGycHFxgYaGhswvFn4CTNaGQIHl5WVUVVW5SiXubd/e3iBAnp6exl5hfn5+OuqLna3Y4SY/zFANFwuyQS8rF+dOcf5M9fCmKIuAiqxeWlpCb2+vK3MCNRSoeNdZWFiIkpISNDc3o6urC93d3bAsK20CE6gGoF43RbIpOLGcQAnUy3gBZB+JebHm59lQ5tdPX36cQ2XxxsuZoczQTMfKn3rMUMQ+xUz8jJNr6N8x5Oc0KBuWfvoi0F+YBglUpoBLOadcTrmuQ8fPaVA2Pv30xSmXU65svPHqz6tCzFCuoa5jRtuU63UUs755CvAffs1johQRgSrJZ15jAjWPiVJEBKokn3mNCdQ8JkoREaiSfOY1JlDzmChFRKBK8pnXmEDNY6IUEYEqyWdeYwI1j4lSROm/2lUyzcY6FCBQHaoH6JNAAxRXh2kC1aF6gD4JNEBxdZgmUB2qB+iTQAMUV4dpAtWheoA+CTRAcXWYJlAdqgfok0ADFFeH6W97Qt2suZ3FFgAAAABJRU5ErkJggg=="/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-79"><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 238px; margin-left: 347px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">HTTP</div></div></div></foreignObject><image x="332.5" y="232" width="29" height="15.75" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHQAAAA/CAYAAAAxBeyIAAAAAXNSR0IArs4c6QAAA/xJREFUeF7tm78vNEEYx78rEoUG0VGJHxGJSIiIQuFHkKAglCRErVKQUChIUPgDRChPUIqCwu9EQSHRiEgkNKIhUQg5mXvf2/f23tubW7Nr5jbf7dzMPM8z388882uXFY1Go+ATGgUsAg0Ny1hHCDRcPAk0ZDwJlEDDpkDI+sM1lEBDpkDIusMMDTPQ1dVVjI+P213s7OzE3t6eUpeLi4vx8vJi27i6ukJdXZ399/7+Pjo6OpR8yBqPjIxgfX0dv+krMabS0lI8Pj7KwnSU5+fno6CgAKJtY2MjWltb0dPTg9zc3LR2HBlKoJ40T1k5PnhUgaYyLuDOzs46ki65HoGqM3RYCBJo3FFfXx82NzeRl5f3X/TagT49PWF3dzcjWaenp/H8/GzXnZqaQllZmbRtZWUlWlpa8Ju+0mXo/Pw8KioqXOP++vrC6+sr7u/vcXZ2hqOjIyRfuQ8MDGBra8s8oFIaCRXKy8txd3dn/3J+fo6mpiYvJjKu66ev5DXUa9y3t7exafbw8NARfyQSwdDQkOM37RmascIA/BRZ5tdPX6pARawfHx9ob2/H8fGxHXp1dTVubm4IVAZTlJsGVMR0fX2N2tpaR/gie0Ws8YcZ6kLXRKAi1JqaGkdWbmxsYHh4mEBlWWoq0MHBQcdmaHFxEZOTkwSarUDHxsawtrZmhz8zM4O5uTkCzVag4riys7Njh7+ysoKJiQkCzVagyUvB9vY2+vv7CTQbgV5eXqK+vt4OPScnJ3bRUlRUlBlQcZuRuIOSiZCqfGFhAe/v73ZR8uW8F5t+blRkfv305dc5tK2tDScnJ3boqV6epD22yDr9k3ICBbzeFD08PGB0dBQHBwf/MtGycHFxgYaGhswvFn4CTNaGQIHl5WVUVVW5SiXubd/e3iBAnp6exl5hfn5+OuqLna3Y4SY/zFANFwuyQS8rF+dOcf5M9fCmKIuAiqxeWlpCb2+vK3MCNRSoeNdZWFiIkpISNDc3o6urC93d3bAsK20CE6gGoF43RbIpOLGcQAnUy3gBZB+JebHm59lQ5tdPX36cQ2XxxsuZoczQTMfKn3rMUMQ+xUz8jJNr6N8x5Oc0KBuWfvoi0F+YBglUpoBLOadcTrmuQ8fPaVA2Pv30xSmXU65svPHqz6tCzFCuoa5jRtuU63UUs755CvAffs1johQRgSrJZ15jAjWPiVJEBKokn3mNCdQ8JkoREaiSfOY1JlDzmChFRKBK8pnXmEDNY6IUEYEqyWdeYwI1j4lSROm/2lUyzcY6FCBQHaoH6JNAAxRXh2kC1aF6gD4JNEBxdZgmUB2qB+iTQAMUV4dpAtWheoA+CTRAcXWYJlAdqgfok0ADFFeH6W97Qt2suZ3FFgAAAABJRU5ErkJggg=="/></switch></g></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-80"><g><rect x="220" y="488" width="310" height="123" rx="7.38" ry="7.38" fill="none" stroke="rgb(0, 0, 0)" stroke-dasharray="3 3" pointer-events="all"/></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-81"><g><path d="M 265 399.37 L 265 428.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 265 394.12 L 268.5 401.12 L 265 399.37 L 261.5 401.12 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 265 433.88 L 261.5 426.88 L 265 428.63 L 268.5 426.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 409px; margin-left: 265px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">LDAP</div></div></div></foreignObject><image x="250.5" y="403" width="29" height="15.75" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-82"><g><rect x="32.5" y="589" width="85" height="20" fill="none" stroke="none" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 89px; height: 1px; padding-top: 599px; margin-left: 31px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">data-db</div></div></div></foreignObject><image x="31" y="592.5" width="89" height="17" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-83"><g><path d="M 42.5 428.63 L 42.5 393" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 42.5 433.88 L 39 426.88 L 42.5 428.63 L 46 426.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-84"><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 412px; margin-left: 43px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">AMQP</div></div></div></foreignObject><image x="27" y="406" width="32" height="15.75" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAAA/CAYAAAAoosBrAAAAAXNSR0IArs4c6QAADUhJREFUeF7tnHeQFEUUxh+ISDKAKEEBQTIUKskIAorIkXMSYwkKJhRFECQYMICgIjkntQo9wJKoYI6FoIgKCIogJgwlBlDgrF9X9VRvb5ievbkT7ub9dbfb3dP9+usXvtezBbKysrIkknyrgQIRAPLt3quFRwDI3/sfASCf738EgAgAURCYrzEQxQD5evujIDCfb38EgAgAQXmAJk2ayFtvvRWjuOXLl0u7du3SUuaXX34p1apVi+s7ceJEuf3229Ma0+y0detWqVmzZtw4L730krRt2zat8T/++GNZuXKlfPDBB7J9+3b59ttv5c8//xTCqRNPPFFKly6tnnnuuedK69atpXHjxlKwYMHAz0qmm1QDFShQQE466SQpWbKkVK1aVc4//3y1zgsuuCBht0AxwOeffy61a9eOG4jNBwTpSLJForyNGzemM2RMn2HDhsnYsWOzDYDDhw/LvHnz5IknnpAtW7YEmlfFihUVmPv37y/Fixd37psOAJINXr9+fXnyySflkksuiWkSCACDBg0STqYtxx13nHzzzTdSvnx558XphqkWuWnTJjnnnHMCj6k7cCLPOussNTdbgliAzZs3y1VXXSWffPJJ2nOhY6VKlWTatGnSqlUrp3HCBAAPxAqNGTNG7rvvPu/5zgA4ePCgnHHGGfLzzz+rzmz23r17vYEefPDBmIGdVigi9iKZ5JEjR1T3O+64QyZMmOA6VFy7devWyWWXXaY+N8flf1cALFu2THr16iV///133PiY+ubNmyuQnXbaaXL88cfLjz/+qPTy+uuvy9dffx3XBxP92GOPyeDBg33XZeuG8RcvXpyy3z///CO//fabYK1Z/2effRbX/qmnnpJbb71Vfe4MgEWLFqlToGX69OmCed23b5/6qEqVKmozWWAQsRfZqFEj+fDDD9UQKBX/ysLTkWuvvVaZbaRevXoxJ9gFAOvXr5eWLVsK5t8UNn306NFy8cUXp/TtKJ+D8dxzz6n4wBRAcPfdd6dclq2bE044QQ4cOBBIFWvXrpUbb7xRdu3a5fUrUqSIEBvhmpwBcOmll8obb7yhBilUqJB8//33cu+998rMmTO9gV955RXvxLnO0l4koHr44Ye97kuXLpUOHTq4Due1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"/></switch></g></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-85"><g><rect x="10" y="435" width="130" height="40" rx="6" ry="6" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 128px; height: 1px; padding-top: 455px; margin-left: 11px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; overflow-wrap: normal;">Data Service</div></div></div></foreignObject><image x="11" y="448.5" width="128" height="17" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-86"><g><path d="M 75 481.37 L 75 500 L 74.63 518.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 75 476.12 L 78.5 483.12 L 75 481.37 L 71.5 483.12 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 74.52 523.88 L 71.16 516.81 L 74.63 518.63 L 78.16 516.95 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-87"><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 498px; margin-left: 75px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">JDBC</div></div></div></foreignObject><image x="60.5" y="492" width="29" height="15.75" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHQAAAA/CAYAAAAxBeyIAAAAAXNSR0IArs4c6QAACm1JREFUeF7tnAWoFG0Xx881Xrsbu7sTuwsVxU5QTLDF7m4xMRC7CyxssTsudjcGJrZer/fjN3yz3+zszM7uvbvDu/ebAyLuPvOcec7/OX3WsKioqChxKNZIIMwBNNZgqRzEATR24ekAGsvwdAB1AI1tEohl53F8qANoLJNALDuOo6H/b4DeuHFDihYtannsWrVqyeHDhw3XLV++XLp162a5R1hYmCRPnlxSp04tqVKlkmzZsknFihWlUqVKUqZMGfnnn38s9zBa0KFDB1m/fr1Pz8aJE0eSJEkiyZIlU/gXKlRIKleuLI0bN5a0adP6tIcvi65cuSL79u2TCxcuyP379+Xly5fy7ds3iRs3rsI7Xbp0Cu+SJUsqvIsVK+bLttZRrp2AentjAO7Ro4f07dtXMmXK5NPh1EX+AGq2cbx48aRLly4yYcIEyZAhg1/81cV///6V1atXy6xZs+TWrVt+7VG4cGEZPny4tG3bVrh0ZmRpcv8tgKoHQEsHDRqkCBYh+0KBAFTlkyVLFtm/f78gYH/ozp070r59e0EzY0JYi7Vr10qOHDkMt7EE9OPHj7J9+3aPhy9evCjLli1zfe6PyS1RooSMHDnSY09u8KdPn+TDhw/y4sULOX36tFy/fl0iIyM91nKwjRs3CgK2Ij2gCLZp06aGj/EOmL7nz5/LpUuXFDfy48cPt7W5c+eWa9euSeLEia1YK9+zR7NmzeTr168e69OkSSPILnv27JI+fXqJHz++IHM0+OTJk/L69WuPZzD9R44cMTTDloCavfGmTZsU9VfJH0Dr1aun3HJfiMNxcebNmyevXr1yewQfx6H52xvpAZ06daoMGzbMF/by7t07GTBggKxbt85t/ezZs2XgwIGWe1y+fFmJAX79+uW2tkKFCjJ58mSpXr26qQnlcnEZxo8fL2fOnHF7HlCvXr3qcaH/9YCqp0BLevXqpfggLaHt586dkwQJEpgKNyaAqpvWqVPHLegjWMOCeCOsTalSpeTx48euZfi/uXPnSp8+fSwvg7qAhhiXUG/VuAxHjx4VgkmVQgZQ9YWnT5/uoV0EC1OmTAkqoDt37nQz05hKtNcbderUSfF3LmGHhSluonXr1j6DqV1IMDV48GC3Z3fs2KGY85AFlBfv2LGjmwlEOx8+fCiZM2c2FFQgNPTevXuSP39+N00z8u3qArQyb968bv6fCB3XEROqW7euHDp0SNmC9A6Ate4j5DSUg3z58kUJIvCvKmGOJk2aFDRAb9++reSFKpFGEbyZUe/evWXRokWur7lsDx48kIQJE8YET8EnE1M0b95catas6RHphySgSGTMmDEyceJEl3By5cqlaKkRBUJDMW0IUaUaNWoo/suI8HlErFqTzGUziuxjhK7BwyEL6JMnTyRnzpxuR6LikidPHo9jBgLQhg0bKpUdldASs+rXzZs3pUiRIm7vQSXI34JIdMAOWUA5LOkK+aJKlPfatWsXUEDRNooY48aNc+0LWJg+s1LkkiVLlIhcJXwpPtgOCmlAW7VqJVu3bnXJCaGPHTs2RoCS+1EAwAKQllCH1lZ3smbNKseOHRNMvBn179/fLfghiFuzZo0deFrXcs3ewq7CgjcpkMstXLjQtaR79+6ydOlSS0CjI1nKjFSYKCiQsngjfbpilVZF533MnglpDUUbMYcqYW6NuioxreWijYDSpk0bSZo0qaX8GzVqJHv37nWtI3ceMmSI5XOBWBDSgE6bNk0RtEoInMRdTzEFVN0vUaJE0rJlSyW69lZupIJz/Phx12ssWLBASGPsoJAGdNSoUUo9VCWiTm3DQP1cDyjrjIIndX1ERISS61IcIPjZs2eP8m+V6Jdu2LBBmjRpYohRgwYN3GrVdqUsvExIAwowBC0qUTWZMWOGpYb6U5xnM7ovlBZ5Tv2hAT6VjkfVqlU9+FHa27Jli+tzivj4XjsopAFFmHRbVCIgIjCyMrn+AqruR1GdzotK5MGkI/q+7NChQ90uFj519+7dduAZuhpKO4pa5vfv312CAlz6pMECFO0kB9VOG6CJ+FUtrVy5UpluUIn3pGqk7YoEC92Q1VD6qfgqrV97//69YRstEJUilQ9BGMGYSkap0t27d6VAgQJumDE7VLZs2WDh6No32oASTWoDC29Na/2QmD8NbjMJUFelvqoSAQotLiMKJKD6KhDdjwMHDniwZUTk6dOnrs8DWVw4ePCgUACpX7++B9+wiIiIKPwA9Uf+YFbokFsR/qpnz56uZQQCFBuMKNCAhoeHS+nSpZVDqbRr1y5lOi7YgM6fP1/69evnYmNWpNdH4JQJMdWMr8SEcDFoPyXPcuXKKZUx6swqhYWHh0fR9VeJxBnTZTUySaI8c+ZM13Peen2BBPT3799SpUoVZfxRJWqlDGGZTcMFUkMBE1BVMst9ETjgkQKpxNjJqVOnlFHN6FLnzp1l1apVrscZ8yS1Uv1zWGRkZBTzKdre4ubNm4U6qTdCQ7Q1TrPCOHsEClA0kmBDP4ZCVUZ7S/XvHShA//z5I/ny5XMbKSEPHjFihKGomE6cM2eO23f43MWLF3sdxTSTu9G0Bi08rIRLQ/nBL/Ou2oSczjxgmU21MbjEjI1KhO3Pnj0zbQ8FAlAuXNeuXd38JvwBSzvmEUyTSy6q72niprSNby3/z58/KzNF+j4t7gmZ+FJGZD8uElMJ+lzWyCoqQRGjkphdrU8icEFTU6RI4SYj/BfO+M2bN67PrYQaE0BJ6jExaIJ+6o9p+hMnTgglOW8UUw3lHSj3UbTQ/g8GBGbbtm3zyhvAGSgDXC1lzJhRiVWYnGRS3ogAkirV6NGjhfloLVWrVk0IjvSu0RXl6jsXPIwpJpLlBpL3MUrIjC6MVGIUg3FCRkLMSA+o2Vwuz3OpKLPhg7ASVGO0uabKg6ICgZD+wvmiod7mcnke0GihcYE4GymSfqaWNtrZs2dN55i074GPI8V6+/atx+sBCOAULFhQmXLAKjItyEXgsho9U7t2bSWiN7KgLkABDD9kNlZhJCg0g9TBKHzWrvf1ty1er/p/vySgoMTH7bYK3NT9AlWcV/cjCANkbz1R/Vm4oLgMtCq6xNmJntFYs8DKLQ/9+fOnULaix6g1v0YvQOhMcELobEWBAJQDEKjhw/z9GUKgAE2ZMqXSNeEdojvshWZRejx//ryV2FzfE6NQjSJF0U4eGm1gWFh49OiRrFixQmkBkaMSkHAATEL58uWVLkOLFi18Dr/9BZSxTH6Fhlnjl2+YJHhaNZbNJBQdQAlYMOe8A6kBJp6fT0QXSP27IVfqu6RfmFd+8qB2dODLlGDx4sWVFA2+vp492pUin6+Xs9BWCTiA2iru4DNzAA2+jG3l4ABqq7iDz8wBNPgytpWDA6it4g4+MwfQ4MvYVg4OoLaKO/jMHECDL2NbOTiA2iru4DNzAA2+jG3l4ABqq7iDz+x//31G8Hk5HGyQgAOoDUK2k4UDqJ3StoGXA6gNQraThQOondK2gZcDqA1CtpOFA6id0raBlwOoDUK2k4UDqJ3StoGXA6gNQraThQOondK2gdd/AGTpUcp01/CWAAAAAElFTkSuQmCC"/></switch></g></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-88"><g><path d="M 146.37 373 L 193.63 373" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 141.12 373 L 148.12 369.5 L 146.37 373 L 148.12 376.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 198.88 373 L 191.88 376.5 L 193.63 373 L 191.88 369.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-89"><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 374px; margin-left: 171px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">LDAP</div></div></div></foreignObject><image x="156.5" y="368" width="29" height="15.75" xlink:href="data:image/png;base64,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"/></switch></g></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-90"><g><path d="M 75 346.63 L 75 331 L 180 331 L 180 137 L 193.63 137" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 75 351.88 L 71.5 344.88 L 75 346.63 L 78.5 344.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 198.88 137 L 191.88 140.5 L 193.63 137 L 191.88 133.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-91"><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 242px; margin-left: 181px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">HTTP,<div>AMQP</div></div></div></div></foreignObject><image x="165" y="229.5" width="32" height="28.75" xlink:href="data:image/png;base64,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G9VXoOnyyy8X1OuYMWPUf1GsCYZ9b62yB7n88ssnWawIlfWVgVdDu+yyi0qKhKisYX7BLgDghC01DFH/JjHpJ554oqyyyiq5azvC58O45ZZbuhV5crnX35YNN4X99ddfXqJ46KGH1Mngzz77LHmub9++gm3E0uQMgIEDB6pqVRDFCr/99luVcMj5QU0UYtRfnCuX9iABFVW0NN11112yySabuHaXtOM+4llnnVUdjID23ntvGT58ePJ7EQD4ilk3v/vuu+QZJuCaa65RGsGHMJo33XTTioKZaDqqo+UtByEAAJ9MPoYo2kkT8hg2bJgbAGxLGssW5keNGlUxgK233lqh3YfsQaKeKIDA+g8huI6ODp8uVdsbbrhBdtxxR/VvEM/k77rrrs4AWGeddYSvRxOTP3LkSOFDqIaQ4eqrr64+HE0sHWiJySefPLXLUACg84suuqjieBh3FHzxxRduADj00EMF61cTwt1+++2VaqQjPSiEhMqeccYZnWVkD5J7c/l6qYgJof75GllvfcicwA022ECVU+OiBE15GuCFF17o5jaFcEu547etra1iOchbCkICAE02++yzV7wbzVC4BGBUYPzptX6qqaZSanGKKaZQssSYOeeccxLBAhS8BVeyB4n65xzb4osvnnThK3xAyPqmjb6rrrpK2SbcsO0CgM0220xYejThS3ONi699kyYD0y7hdzwDrrzHk7IpJADoG5tKzyN/E8coBADHizhmpIkaNea6jwrjFKom4gQ+frI9yBNOOEGGDBmiAimoTcg3JnDGGWco+wTicAQaiqqae+65ZyEAqNBJwQXT8GNZY3kLQWml3h5//PHUpSU0AOaff375+OOPk2Fw3XwhALB4YVAT15VzV61JRJlQm5oobzpgwAAnedmD1JcZ4K8CBE0+MQG0hwYh5VO4LgX/e/DgwYUAwLZhydBERA2NV60nkiYEZPP8888nPx155JFy+umn97gGYGn+8ccfK2SaCwDCnNxIrevU8u933323G6O4hES5NGFsmZWs8pBgA0DfZ8P6NO+88ybvdo0JvPzyyxVFE/TR6EsvvVR5ApqybAAmw7x6nTX7vvvucwKzayP7HRiW5kem+wmpAVgWsdc0sZxRXiYXANxDj1GmCdV6xBFHdBsnahMDQ5eCIdz5zTffqLh4EWUBgOdaW1uT265cYwKEXPEkIPMZ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"/></switch></g></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-92"><g><rect x="10" y="353" width="130" height="40" rx="6" ry="6" fill="#e6e6e6" stroke="#000000" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 128px; height: 1px; padding-top: 373px; margin-left: 11px;"><div data-drawio-colors="color: #000000; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><b>Broker Service</b><div><i>rabbitmq</i></div></div></div></div></foreignObject><image x="11" y="359" width="128" height="32" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-93"><g><path d="M 336.37 373 L 383.63 373" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 331.12 373 L 338.12 369.5 L 336.37 373 L 338.12 376.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 388.88 373 L 381.88 376.5 L 383.63 373 L 381.88 369.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 373px; margin-left: 360px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">LDAP</div></div></div></foreignObject><image x="345.5" y="367" width="29" height="15.75" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-94"><g><path d="M 265 346.63 L 265 153.37" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 265 351.88 L 261.5 344.88 L 265 346.63 L 268.5 344.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 265 148.12 L 268.5 155.12 L 265 153.37 L 261.5 155.12 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-95"><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 238px; margin-left: 266px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">HTTP</div></div></div></foreignObject><image x="251.5" y="232" width="29" height="15.75" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHQAAAA/CAYAAAAxBeyIAAAAAXNSR0IArs4c6QAAA/xJREFUeF7tm78vNEEYx78rEoUG0VGJHxGJSIiIQuFHkKAglCRErVKQUChIUPgDRChPUIqCwu9EQSHRiEgkNKIhUQg5mXvf2/f23tubW7Nr5jbf7dzMPM8z388882uXFY1Go+ATGgUsAg0Ny1hHCDRcPAk0ZDwJlEDDpkDI+sM1lEBDpkDIusMMDTPQ1dVVjI+P213s7OzE3t6eUpeLi4vx8vJi27i6ukJdXZ399/7+Pjo6OpR8yBqPjIxgfX0dv+krMabS0lI8Pj7KwnSU5+fno6CgAKJtY2MjWltb0dPTg9zc3LR2HBlKoJ40T1k5PnhUgaYyLuDOzs46ki65HoGqM3RYCBJo3FFfXx82NzeRl5f3X/TagT49PWF3dzcjWaenp/H8/GzXnZqaQllZmbRtZWUlWlpa8Ju+0mXo/Pw8KioqXOP++vrC6+sr7u/vcXZ2hqOjIyRfuQ8MDGBra8s8oFIaCRXKy8txd3dn/3J+fo6mpiYvJjKu66ev5DXUa9y3t7exafbw8NARfyQSwdDQkOM37RmascIA/BRZ5tdPX6pARawfHx9ob2/H8fGxHXp1dTVubm4IVAZTlJsGVMR0fX2N2tpaR/gie0Ws8YcZ6kLXRKAi1JqaGkdWbmxsYHh4mEBlWWoq0MHBQcdmaHFxEZOTkwSarUDHxsawtrZmhz8zM4O5uTkCzVag4riys7Njh7+ysoKJiQkCzVagyUvB9vY2+vv7CTQbgV5eXqK+vt4OPScnJ3bRUlRUlBlQcZuRuIOSiZCqfGFhAe/v73ZR8uW8F5t+blRkfv305dc5tK2tDScnJ3boqV6epD22yDr9k3ICBbzeFD08PGB0dBQHBwf/MtGycHFxgYaGhswvFn4CTNaGQIHl5WVUVVW5SiXubd/e3iBAnp6exl5hfn5+OuqLna3Y4SY/zFANFwuyQS8rF+dOcf5M9fCmKIuAiqxeWlpCb2+vK3MCNRSoeNdZWFiIkpISNDc3o6urC93d3bAsK20CE6gGoF43RbIpOLGcQAnUy3gBZB+JebHm59lQ5tdPX36cQ2XxxsuZoczQTMfKn3rMUMQ+xUz8jJNr6N8x5Oc0KBuWfvoi0F+YBglUpoBLOadcTrmuQ8fPaVA2Pv30xSmXU65svPHqz6tCzFCuoa5jRtuU63UUs755CvAffs1johQRgSrJZ15jAjWPiVJEBKokn3mNCdQ8JkoREaiSfOY1JlDzmChFRKBK8pnXmEDNY6IUEYEqyWdeYwI1j4lSROm/2lUyzcY6FCBQHaoH6JNAAxRXh2kC1aF6gD4JNEBxdZgmUB2qB+iTQAMUV4dpAtWheoA+CTRAcXWYJlAdqgfok0ADFFeH6W97Qt2suZ3FFgAAAABJRU5ErkJggg=="/></switch></g></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-96"><g><rect x="200" y="353" width="130" height="40" rx="6" ry="6" fill="#e6e6e6" stroke="#000000" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 128px; height: 1px; padding-top: 373px; margin-left: 201px;"><div data-drawio-colors="color: #000000; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><b>Identity Service *</b><div><i>openldap</i></div></div></div></div></foreignObject><image x="201" y="359" width="128" height="32" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-97"><g><path d="M 455 428.63 L 455 411 L 342 411 L 342 376 C 345.9 376 345.9 370 342 370 L 342 370 L 342 341 L 297.5 341 L 297.5 153.37" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 455 433.88 L 451.5 426.88 L 455 428.63 L 458.5 426.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 297.5 148.12 L 301 155.12 L 297.5 153.37 L 294 155.12 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-98"><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 216px; margin-left: 298px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">HTTP</div></div></div></foreignObject><image x="283.5" y="210" width="29" height="15.75" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHQAAAA/CAYAAAAxBeyIAAAAAXNSR0IArs4c6QAAA/xJREFUeF7tm78vNEEYx78rEoUG0VGJHxGJSIiIQuFHkKAglCRErVKQUChIUPgDRChPUIqCwu9EQSHRiEgkNKIhUQg5mXvf2/f23tubW7Nr5jbf7dzMPM8z388882uXFY1Go+ATGgUsAg0Ny1hHCDRcPAk0ZDwJlEDDpkDI+sM1lEBDpkDIusMMDTPQ1dVVjI+P213s7OzE3t6eUpeLi4vx8vJi27i6ukJdXZ399/7+Pjo6OpR8yBqPjIxgfX0dv+krMabS0lI8Pj7KwnSU5+fno6CgAKJtY2MjWltb0dPTg9zc3LR2HBlKoJ40T1k5PnhUgaYyLuDOzs46ki65HoGqM3RYCBJo3FFfXx82NzeRl5f3X/TagT49PWF3dzcjWaenp/H8/GzXnZqaQllZmbRtZWUlWlpa8Ju+0mXo/Pw8KioqXOP++vrC6+sr7u/vcXZ2hqOjIyRfuQ8MDGBra8s8oFIaCRXKy8txd3dn/3J+fo6mpiYvJjKu66ev5DXUa9y3t7exafbw8NARfyQSwdDQkOM37RmascIA/BRZ5tdPX6pARawfHx9ob2/H8fGxHXp1dTVubm4IVAZTlJsGVMR0fX2N2tpaR/gie0Ws8YcZ6kLXRKAi1JqaGkdWbmxsYHh4mEBlWWoq0MHBQcdmaHFxEZOTkwSarUDHxsawtrZmhz8zM4O5uTkCzVag4riys7Njh7+ysoKJiQkCzVagyUvB9vY2+vv7CTQbgV5eXqK+vt4OPScnJ3bRUlRUlBlQcZuRuIOSiZCqfGFhAe/v73ZR8uW8F5t+blRkfv305dc5tK2tDScnJ3boqV6epD22yDr9k3ICBbzeFD08PGB0dBQHBwf/MtGycHFxgYaGhswvFn4CTNaGQIHl5WVUVVW5SiXubd/e3iBAnp6exl5hfn5+OuqLna3Y4SY/zFANFwuyQS8rF+dOcf5M9fCmKIuAiqxeWlpCb2+vK3MCNRSoeNdZWFiIkpISNDc3o6urC93d3bAsK20CE6gGoF43RbIpOLGcQAnUy3gBZB+JebHm59lQ5tdPX36cQ2XxxsuZoczQTMfKn3rMUMQ+xUz8jJNr6N8x5Oc0KBuWfvoi0F+YBglUpoBLOadcTrmuQ8fPaVA2Pv30xSmXU65svPHqz6tCzFCuoa5jRtuU63UUs755CvAffs1johQRgSrJZ15jAjWPiVJEBKokn3mNCdQ8JkoREaiSfOY1JlDzmChFRKBK8pnXmEDNY6IUEYEqyWdeYwI1j4lSROm/2lUyzcY6FCBQHaoH6JNAAxRXh2kC1aF6gD4JNEBxdZgmUB2qB+iTQAMUV4dpAtWheoA+CTRAcXWYJlAdqgfok0ADFFeH6W97Qt2suZ3FFgAAAABJRU5ErkJggg=="/></switch></g></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-99"><g><path d="M 422.5 435 L 422.5 421 L 268 421 C 268 417.1 262 417.1 262 421 L 262 421 L 107.5 421 L 107.5 428.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 107.5 433.88 L 104 426.88 L 107.5 428.63 L 111 426.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-100"><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 422px; margin-left: 206px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">HTTP</div></div></div></foreignObject><image x="191.5" y="416" width="29" height="15.75" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHQAAAA/CAYAAAAxBeyIAAAAAXNSR0IArs4c6QAAA/xJREFUeF7tm78vNEEYx78rEoUG0VGJHxGJSIiIQuFHkKAglCRErVKQUChIUPgDRChPUIqCwu9EQSHRiEgkNKIhUQg5mXvf2/f23tubW7Nr5jbf7dzMPM8z388882uXFY1Go+ATGgUsAg0Ny1hHCDRcPAk0ZDwJlEDDpkDI+sM1lEBDpkDIusMMDTPQ1dVVjI+P213s7OzE3t6eUpeLi4vx8vJi27i6ukJdXZ399/7+Pjo6OpR8yBqPjIxgfX0dv+krMabS0lI8Pj7KwnSU5+fno6CgAKJtY2MjWltb0dPTg9zc3LR2HBlKoJ40T1k5PnhUgaYyLuDOzs46ki65HoGqM3RYCBJo3FFfXx82NzeRl5f3X/TagT49PWF3dzcjWaenp/H8/GzXnZqaQllZmbRtZWUlWlpa8Ju+0mXo/Pw8KioqXOP++vrC6+sr7u/vcXZ2hqOjIyRfuQ8MDGBra8s8oFIaCRXKy8txd3dn/3J+fo6mpiYvJjKu66ev5DXUa9y3t7exafbw8NARfyQSwdDQkOM37RmascIA/BRZ5tdPX6pARawfHx9ob2/H8fGxHXp1dTVubm4IVAZTlJsGVMR0fX2N2tpaR/gie0Ws8YcZ6kLXRKAi1JqaGkdWbmxsYHh4mEBlWWoq0MHBQcdmaHFxEZOTkwSarUDHxsawtrZmhz8zM4O5uTkCzVag4riys7Njh7+ysoKJiQkCzVagyUvB9vY2+vv7CTQbgV5eXqK+vt4OPScnJ3bRUlRUlBlQcZuRuIOSiZCqfGFhAe/v73ZR8uW8F5t+blRkfv305dc5tK2tDScnJ3boqV6epD22yDr9k3ICBbzeFD08PGB0dBQHBwf/MtGycHFxgYaGhswvFn4CTNaGQIHl5WVUVVW5SiXubd/e3iBAnp6exl5hfn5+OuqLna3Y4SY/zFANFwuyQS8rF+dOcf5M9fCmKIuAiqxeWlpCb2+vK3MCNRSoeNdZWFiIkpISNDc3o6urC93d3bAsK20CE6gGoF43RbIpOLGcQAnUy3gBZB+JebHm59lQ5tdPX36cQ2XxxsuZoczQTMfKn3rMUMQ+xUz8jJNr6N8x5Oc0KBuWfvoi0F+YBglUpoBLOadcTrmuQ8fPaVA2Pv30xSmXU65svPHqz6tCzFCuoa5jRtuU63UUs755CvAffs1johQRgSrJZ15jAjWPiVJEBKokn3mNCdQ8JkoREaiSfOY1JlDzmChFRKBK8pnXmEDNY6IUEYEqyWdeYwI1j4lSROm/2lUyzcY6FCBQHaoH6JNAAxRXh2kC1aF6gD4JNEBxdZgmUB2qB+iTQAMUV4dpAtWheoA+CTRAcXWYJlAdqgfok0ADFFeH6W97Qt2suZ3FFgAAAABJRU5ErkJggg=="/></switch></g></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-101"><g><rect x="390" y="435" width="130" height="40" rx="6" ry="6" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 128px; height: 1px; padding-top: 455px; margin-left: 391px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; overflow-wrap: normal;">Metadata Service</div></div></div></foreignObject><image x="391" y="448.5" width="128" height="17" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-102"><g><path d="M 336.37 465 L 383.63 465" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 331.12 465 L 338.12 461.5 L 336.37 465 L 338.12 468.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 388.88 465 L 381.88 468.5 L 383.63 465 L 381.88 461.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-103"><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 466px; margin-left: 361px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">HTTP</div></div></div></foreignObject><image x="346.5" y="460" width="29" height="15.75" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHQAAAA/CAYAAAAxBeyIAAAAAXNSR0IArs4c6QAAA/xJREFUeF7tm78vNEEYx78rEoUG0VGJHxGJSIiIQuFHkKAglCRErVKQUChIUPgDRChPUIqCwu9EQSHRiEgkNKIhUQg5mXvf2/f23tubW7Nr5jbf7dzMPM8z388882uXFY1Go+ATGgUsAg0Ny1hHCDRcPAk0ZDwJlEDDpkDI+sM1lEBDpkDIusMMDTPQ1dVVjI+P213s7OzE3t6eUpeLi4vx8vJi27i6ukJdXZ399/7+Pjo6OpR8yBqPjIxgfX0dv+krMabS0lI8Pj7KwnSU5+fno6CgAKJtY2MjWltb0dPTg9zc3LR2HBlKoJ40T1k5PnhUgaYyLuDOzs46ki65HoGqM3RYCBJo3FFfXx82NzeRl5f3X/TagT49PWF3dzcjWaenp/H8/GzXnZqaQllZmbRtZWUlWlpa8Ju+0mXo/Pw8KioqXOP++vrC6+sr7u/vcXZ2hqOjIyRfuQ8MDGBra8s8oFIaCRXKy8txd3dn/3J+fo6mpiYvJjKu66ev5DXUa9y3t7exafbw8NARfyQSwdDQkOM37RmascIA/BRZ5tdPX6pARawfHx9ob2/H8fGxHXp1dTVubm4IVAZTlJsGVMR0fX2N2tpaR/gie0Ws8YcZ6kLXRKAi1JqaGkdWbmxsYHh4mEBlWWoq0MHBQcdmaHFxEZOTkwSarUDHxsawtrZmhz8zM4O5uTkCzVag4riys7Njh7+ysoKJiQkCzVagyUvB9vY2+vv7CTQbgV5eXqK+vt4OPScnJ3bRUlRUlBlQcZuRuIOSiZCqfGFhAe/v73ZR8uW8F5t+blRkfv305dc5tK2tDScnJ3boqV6epD22yDr9k3ICBbzeFD08PGB0dBQHBwf/MtGycHFxgYaGhswvFn4CTNaGQIHl5WVUVVW5SiXubd/e3iBAnp6exl5hfn5+OuqLna3Y4SY/zFANFwuyQS8rF+dOcf5M9fCmKIuAiqxeWlpCb2+vK3MCNRSoeNdZWFiIkpISNDc3o6urC93d3bAsK20CE6gGoF43RbIpOLGcQAnUy3gBZB+JebHm59lQ5tdPX36cQ2XxxsuZoczQTMfKn3rMUMQ+xUz8jJNr6N8x5Oc0KBuWfvoi0F+YBglUpoBLOadcTrmuQ8fPaVA2Pv30xSmXU65svPHqz6tCzFCuoa5jRtuU63UUs755CvAffs1johQRgSrJZ15jAjWPiVJEBKokn3mNCdQ8JkoREaiSfOY1JlDzmChFRKBK8pnXmEDNY6IUEYEqyWdeYwI1j4lSROm/2lUyzcY6FCBQHaoH6JNAAxRXh2kC1aF6gD4JNEBxdZgmUB2qB+iTQAMUV4dpAtWheoA+CTRAcXWYJlAdqgfok0ADFFeH6W97Qt2suZ3FFgAAAABJRU5ErkJggg=="/></switch></g></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-104"><g><rect x="200" y="435" width="130" height="40" rx="6" ry="6" fill="#e6e6e6" stroke="#000000" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 128px; height: 1px; padding-top: 455px; margin-left: 201px;"><div data-drawio-colors="color: #000000; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><b>Auth Service</b><br /><i>keycloak</i></div></div></div></foreignObject><image x="201" y="441" width="128" height="32" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-105"><g><rect x="390" y="107" width="130" height="40" rx="6" ry="6" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 128px; height: 1px; padding-top: 127px; margin-left: 391px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; overflow-wrap: normal;">Search Service</div></div></div></foreignObject><image x="391" y="120.5" width="128" height="17" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-106"><g><path d="M 430 195.6 C 430 190.85 441.19 187 455 187 C 461.63 187 467.99 187.91 472.68 189.52 C 477.37 191.13 480 193.32 480 195.6 L 480 242.4 C 480 247.15 468.81 251 455 251 C 441.19 251 430 247.15 430 242.4 Z" fill="#e6e6e6" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 480 195.6 C 480 200.35 468.81 204.2 455 204.2 C 441.19 204.2 430 200.35 430 195.6" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-107"><g><rect x="412.5" y="251.5" width="85" height="17" fill="none" stroke="none" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 89px; height: 1px; padding-top: 260px; margin-left: 411px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">search-db</div></div></div></foreignObject><image x="411" y="253.5" width="89" height="17" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-108"><g><rect x="390" y="353" width="130" height="40" rx="6" ry="6" fill="#e6e6e6" stroke="#000000" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 128px; height: 1px; padding-top: 373px; margin-left: 391px;"><div data-drawio-colors="color: #000000; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><b>Dashboard Service</b><div><i>grafana</i></div></div></div></div></foreignObject><image x="391" y="359" width="128" height="32" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-109"><g><path d="M 75 147 L 75 168 L 74.65 182.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 74.53 187.88 L 71.19 180.8 L 74.65 182.63 L 78.19 180.97 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-110"><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 166px; margin-left: 75px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">S3</div></div></div></foreignObject><image x="68.5" y="160" width="13" height="15.75" xlink:href="data:image/png;base64,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"/></switch></g></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-111"><g><path d="M 240 523.6 C 240 518.85 251.19 515 265 515 C 271.63 515 277.99 515.91 282.68 517.52 C 287.37 519.13 290 521.32 290 523.6 L 290 570.4 C 290 575.15 278.81 579 265 579 C 251.19 579 240 575.15 240 570.4 Z" fill="#e6e6e6" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 290 523.6 C 290 528.35 278.81 532.2 265 532.2 C 251.19 532.2 240 528.35 240 523.6" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-112"><g><rect x="222.5" y="579" width="85" height="20" fill="none" stroke="none" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 89px; height: 1px; padding-top: 589px; margin-left: 221px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">auth-db</div></div></div></foreignObject><image x="221" y="582.5" width="89" height="17" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-113"><g><path d="M 430 523.6 C 430 518.85 441.19 515 455 515 C 461.63 515 467.99 515.91 472.68 517.52 C 477.37 519.13 480 521.32 480 523.6 L 480 570.4 C 480 575.15 468.81 579 455 579 C 441.19 579 430 575.15 430 570.4 Z" fill="#e6e6e6" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 480 523.6 C 480 528.35 468.81 532.2 455 532.2 C 441.19 532.2 430 528.35 430 523.6" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-114"><g><rect x="412.5" y="580" width="85" height="17" fill="rgb(255, 255, 255)" stroke="none" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 89px; height: 1px; padding-top: 589px; margin-left: 411px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">metadata-db</div></div></div></foreignObject><image x="411" y="582.5" width="89" height="17" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAWQAAABECAYAAAC2wE+iAAAAAXNSR0IArs4c6QAAFi5JREFUeF7t3QPQbb2SBuC+Y9u2bdu2bdu6Y3vmjm3btm3btrWf+ldqulJL2d9e39nnVHfVqXv/b2dlJW+SN53uTq/7RUkhUAgUAoXAVSBwv6toRTWiECgECoFCIIqQaxIUAoVAIXAlCBQhX8lAVDMKgUKgEChCrjlQCBQChcCVIFCEfCUDUc0oBAqBQqAIueZAIVAIFAJXgkAR8pUMRDWjECgECoEi5JoDhUAhUAhcCQJFyFcyENWMVQS+LyKeP5V4z4j48MLsqhF4/4i4f2rht0fESyy0+Ici4rnTb+8aER991b07qHFFyAcBW9VeFIEi5IvCeSuVFSGfAXMR8hmg1SO3jkAR8q1DfuMXFiGfAWER8hmgXekjjx8Rbzi17eci4uuutJ3nNOuaCfn1I+IJp059fET83TkdvAefKUI+Y1CLkM8A7UofeauIeMDUts+PiDe40nae06xrJuQ/j4hHmzqFmH/vnA7eg88UIZ8xqEXIZ4B2pY98YUS8ThHyrY7OE58w/630xiLk/wejCPmMqViEfAZoV/rIb0fEExUh3+rovO4J8y8oQp7FvAj5jKlYhHwGaFf4iCOzo3OTMlncziB9ygn3tyxCLkK+1HQrQr4Ukne2npfvnHhFyLczHj97wv0ZipCLkC813e5mQv7QiHBBoMm7RcRHpf9+8Yh4vYh4joh4rIh4oIj4m4j4pYj42oj4nIj4txkgHyEi3igiXiYiniYiHjEi/jki/iwifjgiPi8ifvDMAVC3erXNQn7UiHikiPjHiPiriGB2+M6I+KaI+M2Nd3xwRLz3QDtecSPy4oEj4nkj4mWntj1pRDz8CdOHnvoveuDXIuInIuJLI+JXBt7dF32+0/OvFhH+9zEjAi4w/t2I+JGI+JIJ6/bcTZx6Tx0RrxARzx4RTxkRjxwRDxsR/zFFRPx+RPxkRHzjqf/ffbrM8L8r/XqQE+b/OdDvn+8Ie+5R/behuviirf5b+6xNmJt3P33C6ntO8/GrFubsQJPOLvpkEfGaEfGSEfG409yF4R9HxM9Ma+prIuK/pjfcxGTxLicMPmaq50Ej4pUjwvx9xoh47Ijwt7+MiD+a1suXn8r84tk9u6IH72ZCRsZIuckHTjeDkIgF/VIbOP/ORI6/msoZ+M+cSHjtcRrom6TJtzWkDxER7xQRNg3t25L/iQhOOoRrws/JJQnZJmEze4qthqXfvyUi3mylfUvk82mnBfxyO96jfmF8f3Eiq++NiBdIz+y5qfdUJ6w/7kTwL7bjXa2IufDGpw3zRxeeuSQh2+jNX+9DMHuEQmEOffaewhcq8+CnzeEDTkrDO0eE/q+JDZtj2Qbilh5SbjJyU89aMXY2UeuAcrAm1sunT9j804X6fUequZsJ2QTJ1yv9fwRGk8jXMNeAFaL09Cey/IeTdspBg2j3YvKJEfH2O0aNRkbjpamPCjJCKDStXi5FyO8TER802rCpPK3+eU6a06/veN5pwAlja3Hlqn4jIp7rpNnSgF44/bBFyK7ofuVpfjzMjnb1Rf47Il4rIr5i5tlLEfITTJrdk5zRPo98ckS87ZnPjjzmVAnHVxp4yEnnRaZ/eV6NEPLbTaTutPhQA++29ili/z7wzFUV3Us+V9XoqTHIUCB+E5PUZHj36Q/fHBH+0TAtzGeZNC7H4yx2ciYMR3Ga7F9HxBdNx1imhMeY7uA79ma87MqOwEhjSRz31Utby/ILk3f+x6f3PdyknXqH42t+j2Prs3bhVerSp0Y4HzGZZ9o7kEm/WfztzERlNkB2Wf51IiP5Bf5wOiJrn74q/8xdeWYWR+2tRfD9k4kiP84sQ7OBA+2P1shM9OoR8YJTQZsZDZKZp8kaISM5Gpo2N2GGQAj+CVOjRT1kRLhM4wjuhIB8muiLfv7yzMCaD8QGYxyzPNuEWfsb84b5lOXBpv5m27PfbbpfPZmCjJX2MF8wIzEV9JuLE9rRmrJT5/t27TcfnSK/IyL+dDJpCfdj6jJuNq0/mZSbbFIcIWTKFi2ZeYL8VER8w2mOO9UaOybIF53e2Wvtt7VZzUyNm//pbiZku+gnJAjYGWnG7MJ29O+agccAs1E+XvrNILNFsWfakU3+fhEp/iqTtpCrbWaSpZFwPH/z9CNiMEmZBxD6nOgDW1y7bKCMvr3Qin2zf88epx6SQ4hIqQksaKJrlxscmW0AWd6hG4u+X3PY2QiYJGwAc2JxCylDYAgKWTdZI2TmKmPYBLkiC2O7JMgf8WdtzE1HdsslQcwIKcueOGRmHptQlvc7EZkTz5L92hghtCdPD3m3MMc5P8hKs3f/9DiTsmHjasJvYGO0Xubk6SYc2Zj7MRshZL4EWFKI+HPYzueEosL2/+jpRzZsCsKaorQbhNsueDcT8tucHDSfNAMYjefbVoB0g+1zZ35n/6IV/cvKs+rNmhqibJpc/9gzTZpa/vt7RcSH7RhkmhYNNdsW2bcR9ZycQ8hwYqfNom80ny1x8sg2ehrumkmG08wJpQmsOWi2yIR99bNmGrNEyJxhNO2sNcEb7lsiw9hHdgu7OVznnj2XkGFlfJuwVzPLbAnycdrKsjXXt+pc+53SwLnWhLaP6LaczU6Dok9spFlGCNlzNifzcW0jVY7JrHey7zUn3gSfQ5691wj56yeP+hpYNC0acN93jia77Zq8xWk3/tRUgA3V0XVOHCft7k3kl0D4S5pxXwctijbVBHm+9MK7ziFkGqgYWpq4PsDD/65FGbTX96YOdlcmgrnNjHbXa9xwmdsU++5pEw9+f7xfImRkwIylT/49ymTumbPB9+/qY7n9zhaNSObkHEIWyWJTdeRuuOtLPumtzT8aKtNREylIs1lgY/oO/ZwvGnnQaUXejj2iP06wWUYJ+cu6k87ae60Nm1MTprZ8Ct7T5qsoc68R8h5SBTwbF/tcE84ziwSxrAmzBltoFousJ1meaUe2fNyjmTMl7BUkRNNoom3aLNynl3MIua/DXNhDxp4TAtU78hyfHTV7QfouUDSBFaKEzx5hDuFxz7Ll1GtlR/rkmX5erG0c5xDyXH9H2tibY0ZIcg/WrQzS78Ma+TcoPHukn7ueGSVktnOnxD0yd+rVByexu0ruJUJGJhx2Iia2hNOHSaEJp94eT7IIgd42RTNk68oiXOfH0h+0zQJG/HvF2LATZvsYDbk3M6jvEoS8t13KIdR+Y6D902Z76W+zcYSJbNkr7Kb9wtpLyHvf0cqJUXcsb8K59LELlVyKkEfayGH11ukBJ7o9IYQj71B2ztnLfLN3E1WHudscoP57hJC9x2ltS0Fq/RK10isDaya+UTxurfy9RMgjxxQ2J7anJuJB91yy4BTsHRomDtNFlt7hKNKDk2RUTOIcRytE7UNmKrltQrbx9YuTjZM3vJf+UodIAk6+veIEwhSSbZJHETKzUt4s1r5ccScImTkmR8+w5YsQubT0lzqY+GzCI+KSDUd0kxFCdgrNcedb7xWRwjmc58jSWtmq647+fi8R8ojm1ZNEf8tvaVDmFuEcITtiO2o34QjJ9uC9g05Dywvui1NGt1zHJQiZrde7eMrZYtnaOclEHvTzxH/TmLIsEbIwM1nRmtA49WtE4JdjdvcSsks4IiychoTTOW3okxCyHObW2mKjsQE0OZqQOR+Fb3HqPe1k99Q+/+YuYQijFJrZ5ChC5kjlUG3i5NOHO26Nn9A4oXlNRgjZ+9906wXd7/084/Dv7diDVd5+8XuJkLc8/RndnpAF2TsObsleQuawOiIf8dICvAkhs/chSRrJTebDEiHnfMHwdesr3+DawtzvCEFURpMtQuYw4/AS/pYJbM+7cpmjCJkmp26b9qjmmdu3NB/E4tuI9orwvmyCEpLIbNFkVGP1nDn1jqmOEULeGxmT+9fnFbEGs1N9LxZ3tNxNFuAdbfjJTNCHvV0TIfOkr8WwnosdUwvHYi/nEjIthI1360rsnvYuEbLLOjm+9z1m4pi36u9NTGuETJMTutdr8FvvmPv9CELWLjHyeYM5p22eWSLkXsPdql/ccDbF9WGNwj1zFMNWfX53S4/ZoMkIIbuMIi57RNwCzeGDbhjmTWWkrjtWtgj5PugvrSG7KfeqB4wqLSA7I9srziFkccScQv3R3fVTNxVppRYph6UkMllGbMhse1lL3dJu52DrY3eX6mDjZ7rqyZjJA0ZifoXgtVuLfVTJ0TZkWNtc+rhjt9+0j91VW2mrYrT76J29NuSbEvK3dl+IXiPTpWnu8hBT4DmETMPPMeF7llL/5Wpa/mvsefCayhQhH0PIvf1Mcpzs4Lj0HBglZBqxRDrZLutGmyO+iJMtGSFkDk/5PJps3W6ce3cf/bBEyDLx9bGyHLaux7csZGt9O5qQ58KzkB3c90Qw3BYhuxknSqHJD0zZ6LbmRf69jwgZ0ZAvYdY6xw490r9DyhYhH0PI/S2nc5wiIwM+SsiuR/dXy13x/oydL+UckxYyy5LJgkaar2dzeMpTMCK9HXqOkJlF3NITA95EmlCJgvaKTSpnvLu0yaI3vbh8wZm3dH28b7dLSS4nNTnKqddvbEsnszVcezv0CCGfM0d6x6/NK9uw986BO1quCPkYQu7zFZwTNjQyMUYJuc8l7YgsLK83TSy1oY+zVm6JkHtzA/t61r62+ilSov+S8xwhCw/sb9Ux7+TLNWvvYk4Qwy6SocklCdklIeafHMXR0kxuYdB+700JRxFyb26w0eVTzp729qeNEULec+M2twGP2dTyZpxzKu9p71WUKUI+hpA5bPpLEnsSz5w7KUYJ2Q0v6UabsBvn9JZb7ZhL2blEyL22xfxAK9wrTD1sq1nmCJlHPWc/k3uB7XrvVfW5nAiXJGQ3GWnEWTho937sAKE7KQiJa3IUIc+ZVkSDzCXdmhvHudPKCCELYRtJ0+qatA8NZOEjsYHdVVKEfAwhs9HSKvLiWbv1ddNJM0rI7MSuwjZxJfe1dzZCwiMLps8VsETIfdIejjSx23sXty9H9CaOOULu07G6Bt3SN+7pGvNG7wS6JCG7cEJrzOIK+laynlaeSck4ZzmKkOcSGY3cfBNyJ11mlhFC9pzYddkH90j/sVnP9JEje+q542WKkI8hZLX2JLk3b3CeFFJCChsTxuWf24hz0r/LVxZ8vmpJeq2VJrH1hZVWF+83oupF2lCpTXuZy2vADtqnoJxrqw3Nldj+uDxHyL1WBzfX2vdoyK6kizjp14Pbm/mrNLmNczHpayQyd72X6afP4DaHA3JheulxkAlt5IsoewmHWYU2nt83kuzHXHXhJcsoIQubk5Z0j0iVKo94k5FLYnvqv7UyRcj3QX3psDd1zmlEtL2c0nBtoLVJGsEmcgNwjs19082tJHHZTbbiRsUC5zSgfz8lV1pLPapucZ0WpvLMATmczYLotaLWHpoOk00TJAufPgdIj0fvqW+/zxGy9J/9p5eWNon8Hk48IVPIh6My519Ycy4p31+Z1wY28zlxamILzzbqNcJvddhUjOdzzrTvHGfbXnLxzUn5qpvIKyHGeytz3lzua3WMErK5wbTVmyL69jMPyk2TuUxUjWieu06KkO8bsiMIWb29V9zffGpK4PtSLmAmAXGYJlQeH4T7gIUZJkwoaxMmM42M2WRO5CaWozjLGvlok9t1iFCbHJ95sHNEgsiSHHea6+7NCX5b+xgA54ycHe2KNUJng20yR8jaKHlT/iIMgmaDXsLaBiM8iibOZGGjyVEMMMq5i3OfEKx6s5NuKyeKE09OoWp8jMVcljzvco1dCBp7KgxojTltqc2Z+Ue7Ly1ONvwgeQ4iR+aIpQ+KMh2I1LFROxHmK/NrhOxkZcNp0pLbyygoedJSsnlzQrRQ3uzNfeGcI4m8Lo3d2fUVId8H3VGEzLlhUfefcPqD6UOsJqKjIQ+/9J8WPztmDhPTPkdAuXmX0mO6FdgnrxduRstRvzA1i9d14ib9IvB33m2biOxq5gY7sa8hc5gheEILZn92EypHS/ByS7VJ2xQZkZ2ayNLnkHpHDQ2Txg0ji5DWiQjU25Ixyd+h3z6e2WRJs+yjR5R3fGVmYRpAoK5VMxWor5EArBCjeOD+owdOEkxACFi5rNXTFpFmE+3UXpn+EDVicBOyZaubiwQR4WJcbFAI2oaiTtkHjat6RL8YB58v6smQHdmGTPt2wln6KO45JDEX160tfBAcreaWvCD6qa0tbzUytsHndARr5hUbZ/7AAYWEWYwjUXw8TGU5tCGYZ3wD1oObpv2nrc65VHIONoc8U4R8LCGrHcmwT2YNYGQwaQAIkE10SXjg3apbuy5sAfn4ZBObBJLKR+itdokIoOEhpaUvr6hDW/uFIo0msh7J3SAnr1tttO+cbGbpSLq0Aa71iylIhIkYZBoXh+XSuugdl3Ofs+rf1ef1Hc1zYiPlcLUBahdNuW2O/bvWnJBbYzv3u7lh/o18oNfckBfF6QmRNlm7HNV/UcbGSMNFwjmUbasPbpjynezN671V363/XoR8PCF7gyOcRDIWcP423NqAm5A0PhrbHscU2x1tMx+hc/09IfvNQpMOk3a+Jm650fTYntslBglyLKSsIbY65gjZb5KGMxHs+WSRxejWHS26j7RYMw2wAevTnnc4echqlvM4zJmZWr96QkYWbrEtmTU81xOy0wLNcU/2PxEY7LjyNDRxgmJemZNLE7J30Nhpu3uSZTExIFO27T7Swols6WvwTjE5FFLWQZo/7JxO+hNj33dau9hpZr49NzJvnWj3vrAI+XYIuY0HBw0Nkweag4T9jwZtR3cpgS3RMZi9zYTc+uZcP84mPNJHRhaSIy5CE/vLHOEI2gvt2qK3CDjaaNlMKI7PjtpilC2KuQ+farvjMjsfIqQd0eC0fSmjmzknosOR3KmBOYWJA4nrv+OrMLwcn+ubeDkP9FZqRe/QJp+pYp7wDuSpfTRg5GDzyh8RaLjY0NiuaVqO4jRUhC1DIDt9n5ifFslRK3dJs5kyHzBLcTZp95wZgTNKekqxyMwz7NhMDiJp5JU2Xv7NJWnnQPVOJgIEzxnJmegkMZeTei8frJVzyQaeThNMBk46iFB4oX4yY9gIGyGag3kjYWqZ27y9s3f6ZmescbMJGU/99dUc5iPjAGMbt/nSx3hfos+3XsfdTMi3Dla9sBAoBAqBIxEoQj4S3aq7ECgECoEBBIqQB8CqooVAIVAIHIlAEfKR6FbdhUAhUAgMIFCEPABWFS0ECoFC4EgEipCPRLfqLgQKgUJgAIEi5AGwqmghUAgUAkciUIR8JLpVdyFQCBQCAwgUIQ+AVUULgUKgEDgSgSLkI9GtuguBQqAQGECgCHkArCpaCBQChcCRCBQhH4lu1V0IFAKFwAACRcgDYFXRQqAQKASORKAI+Uh0q+5CoBAoBAYQKEIeAKuKFgKFQCFwJAJFyEeiW3UXAoVAITCAQBHyAFhVtBAoBAqBIxEoQj4S3aq7ECgECoEBBIqQB8CqooVAIVAIHIlAEfKR6FbdhUAhUAgMIFCEPABWFS0ECoFC4EgEipCPRLfqLgQKgUJgAIEi5AGwqmghUAgUAkciUIR8JLpVdyFQCBQCAwj8H8uc5oG8f5o8AAAAAElFTkSuQmCC"/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-115"><g><path d="M 336.37 117 L 383.63 117" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 331.12 117 L 338.12 113.5 L 336.37 117 L 338.12 120.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 388.88 117 L 381.88 120.5 L 383.63 117 L 381.88 113.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 117px; margin-left: 360px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">HTTP</div></div></div></foreignObject><image x="345.5" y="111" width="29" height="15.75" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHQAAAA/CAYAAAAxBeyIAAAAAXNSR0IArs4c6QAAA/xJREFUeF7tm78vNEEYx78rEoUG0VGJHxGJSIiIQuFHkKAglCRErVKQUChIUPgDRChPUIqCwu9EQSHRiEgkNKIhUQg5mXvf2/f23tubW7Nr5jbf7dzMPM8z388882uXFY1Go+ATGgUsAg0Ny1hHCDRcPAk0ZDwJlEDDpkDI+sM1lEBDpkDIusMMDTPQ1dVVjI+P213s7OzE3t6eUpeLi4vx8vJi27i6ukJdXZ399/7+Pjo6OpR8yBqPjIxgfX0dv+krMabS0lI8Pj7KwnSU5+fno6CgAKJtY2MjWltb0dPTg9zc3LR2HBlKoJ40T1k5PnhUgaYyLuDOzs46ki65HoGqM3RYCBJo3FFfXx82NzeRl5f3X/TagT49PWF3dzcjWaenp/H8/GzXnZqaQllZmbRtZWUlWlpa8Ju+0mXo/Pw8KioqXOP++vrC6+sr7u/vcXZ2hqOjIyRfuQ8MDGBra8s8oFIaCRXKy8txd3dn/3J+fo6mpiYvJjKu66ev5DXUa9y3t7exafbw8NARfyQSwdDQkOM37RmascIA/BRZ5tdPX6pARawfHx9ob2/H8fGxHXp1dTVubm4IVAZTlJsGVMR0fX2N2tpaR/gie0Ws8YcZ6kLXRKAi1JqaGkdWbmxsYHh4mEBlWWoq0MHBQcdmaHFxEZOTkwSarUDHxsawtrZmhz8zM4O5uTkCzVag4riys7Njh7+ysoKJiQkCzVagyUvB9vY2+vv7CTQbgV5eXqK+vt4OPScnJ3bRUlRUlBlQcZuRuIOSiZCqfGFhAe/v73ZR8uW8F5t+blRkfv305dc5tK2tDScnJ3boqV6epD22yDr9k3ICBbzeFD08PGB0dBQHBwf/MtGycHFxgYaGhswvFn4CTNaGQIHl5WVUVVW5SiXubd/e3iBAnp6exl5hfn5+OuqLna3Y4SY/zFANFwuyQS8rF+dOcf5M9fCmKIuAiqxeWlpCb2+vK3MCNRSoeNdZWFiIkpISNDc3o6urC93d3bAsK20CE6gGoF43RbIpOLGcQAnUy3gBZB+JebHm59lQ5tdPX36cQ2XxxsuZoczQTMfKn3rMUMQ+xUz8jJNr6N8x5Oc0KBuWfvoi0F+YBglUpoBLOadcTrmuQ8fPaVA2Pv30xSmXU65svPHqz6tCzFCuoa5jRtuU63UUs755CvAffs1johQRgSrJZ15jAjWPiVJEBKokn3mNCdQ8JkoREaiSfOY1JlDzmChFRKBK8pnXmEDNY6IUEYEqyWdeYwI1j4lSROm/2lUyzcY6FCBQHaoH6JNAAxRXh2kC1aF6gD4JNEBxdZgmUB2qB+iTQAMUV4dpAtWheoA+CTRAcXWYJlAdqgfok0ADFFeH6W97Qt2suZ3FFgAAAABJRU5ErkJggg=="/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-116"><g><path d="M 200 117 L 170 117 L 146.37 117" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 141.12 117 L 148.12 113.5 L 146.37 117 L 148.12 120.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 117px; margin-left: 170px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">HTTP</div></div></div></foreignObject><image x="155.5" y="111" width="29" height="15.75" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHQAAAA/CAYAAAAxBeyIAAAAAXNSR0IArs4c6QAAA/xJREFUeF7tm78vNEEYx78rEoUG0VGJHxGJSIiIQuFHkKAglCRErVKQUChIUPgDRChPUIqCwu9EQSHRiEgkNKIhUQg5mXvf2/f23tubW7Nr5jbf7dzMPM8z388882uXFY1Go+ATGgUsAg0Ny1hHCDRcPAk0ZDwJlEDDpkDI+sM1lEBDpkDIusMMDTPQ1dVVjI+P213s7OzE3t6eUpeLi4vx8vJi27i6ukJdXZ399/7+Pjo6OpR8yBqPjIxgfX0dv+krMabS0lI8Pj7KwnSU5+fno6CgAKJtY2MjWltb0dPTg9zc3LR2HBlKoJ40T1k5PnhUgaYyLuDOzs46ki65HoGqM3RYCBJo3FFfXx82NzeRl5f3X/TagT49PWF3dzcjWaenp/H8/GzXnZqaQllZmbRtZWUlWlpa8Ju+0mXo/Pw8KioqXOP++vrC6+sr7u/vcXZ2hqOjIyRfuQ8MDGBra8s8oFIaCRXKy8txd3dn/3J+fo6mpiYvJjKu66ev5DXUa9y3t7exafbw8NARfyQSwdDQkOM37RmascIA/BRZ5tdPX6pARawfHx9ob2/H8fGxHXp1dTVubm4IVAZTlJsGVMR0fX2N2tpaR/gie0Ws8YcZ6kLXRKAi1JqaGkdWbmxsYHh4mEBlWWoq0MHBQcdmaHFxEZOTkwSarUDHxsawtrZmhz8zM4O5uTkCzVag4riys7Njh7+ysoKJiQkCzVagyUvB9vY2+vv7CTQbgV5eXqK+vt4OPScnJ3bRUlRUlBlQcZuRuIOSiZCqfGFhAe/v73ZR8uW8F5t+blRkfv305dc5tK2tDScnJ3boqV6epD22yDr9k3ICBbzeFD08PGB0dBQHBwf/MtGycHFxgYaGhswvFn4CTNaGQIHl5WVUVVW5SiXubd/e3iBAnp6exl5hfn5+OuqLna3Y4SY/zFANFwuyQS8rF+dOcf5M9fCmKIuAiqxeWlpCb2+vK3MCNRSoeNdZWFiIkpISNDc3o6urC93d3bAsK20CE6gGoF43RbIpOLGcQAnUy3gBZB+JebHm59lQ5tdPX36cQ2XxxsuZoczQTMfKn3rMUMQ+xUz8jJNr6N8x5Oc0KBuWfvoi0F+YBglUpoBLOadcTrmuQ8fPaVA2Pv30xSmXU65svPHqz6tCzFCuoa5jRtuU63UUs755CvAffs1johQRgSrJZ15jAjWPiVJEBKokn3mNCdQ8JkoREaiSfOY1JlDzmChFRKBK8pnXmEDNY6IUEYEqyWdeYwI1j4lSROm/2lUyzcY6FCBQHaoH6JNAAxRXh2kC1aF6gD4JNEBxdZgmUB2qB+iTQAMUV4dpAtWheoA+CTRAcXWYJlAdqgfok0ADFFeH6W97Qt2suZ3FFgAAAABJRU5ErkJggg=="/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-117"><g><path d="M 193.63 127 L 160 127 L 160 291 L 146.37 291" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 198.88 127 L 191.88 130.5 L 193.63 127 L 191.88 123.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 141.12 291 L 148.12 287.5 L 146.37 291 L 148.12 294.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-118"><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 198px; margin-left: 161px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">HTTP</div></div></div></foreignObject><image x="146.5" y="192" width="29" height="15.75" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHQAAAA/CAYAAAAxBeyIAAAAAXNSR0IArs4c6QAAA/xJREFUeF7tm78vNEEYx78rEoUG0VGJHxGJSIiIQuFHkKAglCRErVKQUChIUPgDRChPUIqCwu9EQSHRiEgkNKIhUQg5mXvf2/f23tubW7Nr5jbf7dzMPM8z388882uXFY1Go+ATGgUsAg0Ny1hHCDRcPAk0ZDwJlEDDpkDI+sM1lEBDpkDIusMMDTPQ1dVVjI+P213s7OzE3t6eUpeLi4vx8vJi27i6ukJdXZ399/7+Pjo6OpR8yBqPjIxgfX0dv+krMabS0lI8Pj7KwnSU5+fno6CgAKJtY2MjWltb0dPTg9zc3LR2HBlKoJ40T1k5PnhUgaYyLuDOzs46ki65HoGqM3RYCBJo3FFfXx82NzeRl5f3X/TagT49PWF3dzcjWaenp/H8/GzXnZqaQllZmbRtZWUlWlpa8Ju+0mXo/Pw8KioqXOP++vrC6+sr7u/vcXZ2hqOjIyRfuQ8MDGBra8s8oFIaCRXKy8txd3dn/3J+fo6mpiYvJjKu66ev5DXUa9y3t7exafbw8NARfyQSwdDQkOM37RmascIA/BRZ5tdPX6pARawfHx9ob2/H8fGxHXp1dTVubm4IVAZTlJsGVMR0fX2N2tpaR/gie0Ws8YcZ6kLXRKAi1JqaGkdWbmxsYHh4mEBlWWoq0MHBQcdmaHFxEZOTkwSarUDHxsawtrZmhz8zM4O5uTkCzVag4riys7Njh7+ysoKJiQkCzVagyUvB9vY2+vv7CTQbgV5eXqK+vt4OPScnJ3bRUlRUlBlQcZuRuIOSiZCqfGFhAe/v73ZR8uW8F5t+blRkfv305dc5tK2tDScnJ3boqV6epD22yDr9k3ICBbzeFD08PGB0dBQHBwf/MtGycHFxgYaGhswvFn4CTNaGQIHl5WVUVVW5SiXubd/e3iBAnp6exl5hfn5+OuqLna3Y4SY/zFANFwuyQS8rF+dOcf5M9fCmKIuAiqxeWlpCb2+vK3MCNRSoeNdZWFiIkpISNDc3o6urC93d3bAsK20CE6gGoF43RbIpOLGcQAnUy3gBZB+JebHm59lQ5tdPX36cQ2XxxsuZoczQTMfKn3rMUMQ+xUz8jJNr6N8x5Oc0KBuWfvoi0F+YBglUpoBLOadcTrmuQ8fPaVA2Pv30xSmXU65svPHqz6tCzFCuoa5jRtuU63UUs755CvAffs1johQRgSrJZ15jAjWPiVJEBKokn3mNCdQ8JkoREaiSfOY1JlDzmChFRKBK8pnXmEDNY6IUEYEqyWdeYwI1j4lSROm/2lUyzcY6FCBQHaoH6JNAAxRXh2kC1aF6gD4JNEBxdZgmUB2qB+iTQAMUV4dpAtWheoA+CTRAcXWYJlAdqgfok0ADFFeH6W97Qt2suZ3FFgAAAABJRU5ErkJggg=="/></switch></g></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-119"><g><rect x="200" y="107" width="130" height="40" rx="6" ry="6" fill="#e6e6e6" stroke="#000000" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 128px; height: 1px; padding-top: 127px; margin-left: 201px;"><div data-drawio-colors="color: #000000; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><b>Gateway Service</b><div><i>nginx</i></div></div></div></div></foreignObject><image x="201" y="113" width="128" height="32" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAgAAAACACAYAAAB9V9ELAAAAAXNSR0IArs4c6QAAIABJREFUeF7tnQWU9biRhSucCTMzZ8LMzMyMG6YJ8wY3MGHcMPNkwszMzMyMG2Zcf1krq64pyfIDd7/nW+f0+c//LMvSlWxdFelgJhECQkAICAEhIARmh8DBZtdjdVgICAEhIASEgBAwEQBNAiEgBISAEBACM0RABGCGg64uCwEhIASEgBAQAdAcEAJCQAgIASEwQwREAGY46OqyEBACQkAICAERAM0BISAEhIAQEAIzREAEYIaDri4LASEgBISAEBAB0BwQAkJACAgBITBDBEQAZjjo6rIQEAJCwMxeaGbXC5D4tZkdRQhtPwIiAMuN8THN7HRmdgIzO4aZ7WNmBzez35nZb83se2b2ZTP7vpn9c7lH6W4hsHUIHLt/f05oZkcwsyOa2SHM7Pf934/M7Otm9k0z+8vW9X73OyQCsPtjsKstEAEYBz94XdzMrm5mlzKzEzfe/gsze4uZvdbMXqmPWSNqKrZtCPD+8N7w/lzBzI7V2ME/m9l7+/fnuT3BbrxVxSoIiADMfHqIALRNAHC6breLv7+ZnbLtlmKpH5jZIzuNwX+b2d+XrGvdt7+j+/BeNHvI483sjut+qOrfSgSYR48ys7Ms2TvI9P3M7ElL1qPbZQKY/RwQARieAqj3n29mFxkuOqrEh3r727dG3TVdYdSzkBVUsklEAKbDf5uedFcze4TZSlOPowm4iUxrS02TJ5jZVYMa8AHAtCnZcgREAOoDzG7lDWZ23DXNgx/2xOKra6p/mWr3MzM+ELmIACyD6Dzvvc0ad+toAh40T1jVayGwPAIiAGUMT2VmH+id+8YgjVo/3zUP3YuD4JnMDNXmXhL6fl4RgL00JBvXFnxkvtCZvA5fafk3zOx9ZoYmDMdZnGiPZman781POAeW5G9mdureSXDjwFGDhcBuIyACEI/AYc3s4w1qMDyUDzCzt/Xeyj8zs7+a2ZH6D9OFu9+v3zn+nXFgoA80s2vt9mTIno9X9ncCla00AHtokDagKQ/s7fVRU4mQQYX/9ko/WPzvbWb3rJgPnm5mt9wALNREIbDnEBABiIfkwd1C/p+V0SJM6S5m9iwzYxcyJHg947RU83q+QBdh8P6hiia6js0WR0UvIgATDcCWPOazZnaGoC9oySDFX2zs5527EMFHF8r+T/9e/aOxLhUTAkKgR0AE4KBTAec31JHE9EfyczO7TK8hGDORTmpm76qEDhIieKURFZ6sd+A5V68uJScBcdR8XH/Z5x74sJm9qQ9BrOUhOE2ngfjSiGfnRf/DzHDIqsmh+/BJQigxKxynN62g7v2pmeEL8W4ze10XJoZzZEkO1/eN+rygCq75UjCe4HKYQuWEpb1+oB+RWYRbGDfGryTn7MvgU3LaPskKu9s/9m36Wt/vl3VjyqJZk9ubGUQskv/qI1Vah/KZXa6KmxYK4/TKmCwj5MOI1P8QXQhvq/CdAhfMArlAxHlXwZ9cAS2CeYH3l7nIePDeHN3MCDX8iZl9u39fXtNr9VrqROOH41wkF+pDGLmGZg2/hUv2fkWH6n2MXm1mzyjc/1gzgwC1ylX6UOOo/GP6jUu6tsowQN6/S/e4nrzH9ch9yCYk7dO9SfXF/Tvf2h9fbh3jt2hbNv4+EYCDDuF9Ko5FLKJM8rcuOPJn6z4+H8l8BH5sZm/uF2nMCCxQQ7JvR04e3hGQyw8VzK6zwNy2N1VEt62LAOALAUG4r5mdqLG9xHvfof9gRLdgLz5/cOEGfWaz0mP44INxSfzH0ZfjY/0bM8M8lAs7TxaQXwUVX7YfK79w1aAg9BKVNrbxSI7aEybfDspC4pgfLcK7T6IdCK8XzD8Q1mWSV0HWWKAjgehdsaWRWRkWebQGLPTpjwW7Vchsd7fO1wYCVfMrSPUxrhBbTBBDzwFLiHf0PU3kkDnA3Gb8csHJGDMhz4iILfPgFK2dNLMX9PVFt5y1I0ufyi6sggAQLYAjJsSjRUjoRBvvPtLvaZ3j19LurSwjAnDQYeUjyoIYyXN6u+UykwF7Jjtfduaw4jEf2Wt0H+bnVbQTtXbxHD5mDwsKrYMAsCt6aU+YxuKFWYUFHf8KL3xsIGlenth/3EvP2r+3JZeu82HkA1mSc5jZR4OL+IpwLRfeK0gaC84iws75yt0uGTIQCbuo6xSu8UFuUa2fu6JtwQQGaVtGmOP4w/CvFwgGu8Sp8mAwv9Hu8MyxwsJ8sd6ZsXYvZAfS44XFHc3O5ws5RCAAkHk0DiVS1DqmkFQ0alEaX+aED+1blgDcqNdc8NyxQjshR2gph2SK8Rtqw1ZeFwHYOazsemqqRHYgn9ulmUAiFTQPYyIMoqZGO+VVEwA+hB/soxsWhYvF4dqd2vflrgJwiBZGPiTnqTyMxdsv1Hlxdnykcy5pYaKwSO7HV4LdTC4kjHrAoh3v70PbwCIdmWZKGHArz8YUMCQ1QkQEDFqjZQV1eilb5lhzxaJtYdHD5LBMbnvMfucbMDGh5kY97eXW/Q9PKXQgEQCcgCPCy233KhB3XyWmBTKORgL5Z8xzWYYA1PwyWscK0kSb+VaUZKrxa23zVpUTAdg5nOyq2F1F8snORo0KfzcEuzWqwOMXHs4Hjl0GiXvwA7hcn241Kg7zZifELjMJKuz0oeI3dn+ROhL7/Btdpdi+vd362b3qP3r+Jzq1Mx9DdkTMP0gVi2ukJic0Eps5bU6C6ht1u7fl/6mPvmDX6QVbJB/onDyhEfHzHzUm9thIXtRng/TXsCdjxklCf9AmRDtfSA1aEVTBRIwcr9d04CMQCVoizAheaDf+DpFqGII6FHVCfYTnReYCxtiHfxaaN/gz2qobVkphCsAmjiZsHYLfx8cq0Tyk5eZ9h6jgq3DB3vwEEfSC6Ql7fkljhzkF3xYvkEOiHUpaxUQAIM1oGyLzROuYPLUQEUGb2dygecllUQIAGXpPZTPC3Ca6g3/JoYIGJSJHtIVoEMKgI+I95fitY/7t+TpFAHYOUW1XNKRiXudg36ziJIQ9LfrIwvgfUmjUrboX82mVBpect1qiAGq7U2yqOJ15j21UiOx+oqxk3IMfQS58fPhYezl7l2MeguEFVaNf2FlcWbxzIfER/geRQMBwvMwFUwU23ZxMlT6q3Mc4EjmSC6QE9TS+JZGwcHwluMCu8KGFe4YcIiGAhLBGAhFkIVmFsFC0RLbQP3auOB2yGxyyube2DS1DyZTBPISoeoGU4ayLFsTLjXsTXPR8HFmjhGH4nVyiv4GFmMU8EWaexX2JfJdIJu8L5IIFtSR8y6krIiEQTsiLl0UIwCF78gmhiIQU50RI5Yc3Qa743kQnD1IHKaIjc9mU49c6p7aqnAjAzuEsvYCUqr38654ULBDs6iNhh8yJg17YweNk6J2OKPeqwmKb6liGALCjiXat7LJoKzv1SNBcoHb2Tml4Z/NhzXcIqNdRdXsh61ykamVhR8uQy9X63V+uSSjtnvEUz7UQqR4WKxa5JCzmaBrQOHhhLEoZJUv+BdQBIfEZGfmdur5rZnyQvRDCWiIHlC2pbyOsC8PV/HPNX6FUCZ79LJT8sfNmwRzjK0O9aIrYXUa7echmyYeCe0vjgTahpK0hoVdJQ0edXCccGCfgkvCOlyJR0CLgg1QStDZEqURyi8IGYhECUNOS4seA70okfI/o+5mDiySAIuU6Zq8kU49f84TepoIiADtHExt7Yut+nFnU2DXuhuBIFKkGUSmXwodoZ6k/qI/ZJZZkUQLAS8yiFM0rHPdKGonUDq6jufBCBMOTsx9JsMQuzUvJSRNzg3eAYlHHnJH7BbDIQED8TosQwSjMj/bmDok4PnJoVCQsRpCjSDAXYA+NPPtriW5KjmNDDo0lDQr+FjiarlLY/dHvaAfa+px0mibEFbNBiUTm9bHbZIGLhCiS0mKZypdCPjFVYT7xUiMAECu0U8zDmqAJw5SASc4LGqyapz2+KOTv8MKz0QpEUSqLEIASLjwXk1ItnLg2Jmj/GN8kU49f61zcqnIiADuHsxRiRikYdi1GPa8JhzTi88cK6mHUxKuS0gvOBzX6yKTnLkoAWPzQokSCyh58a1IyH/gcCeza+aD5BZMPs/clYEFn951LIkAkZ0JrkMs1e3+K/LcSMcG2+c4VDVZpAcFOjbYikhIxoSxq/sihFVss2ozImRQvdBbYVQsLG1obVMOlPAytz8Qhj5BNTHK56cXfD3G6eVApCyLapshXJC9eUj+jPSE230uNANRMS76ekh0fgog2o0R+MOlEUQ61+TOWAIAbmrho7qClwZZfE7SRpbMb2KzkJHvq8Wudf1tVTgRg53Bir8xVuvlVFvQoDCyaEHuFAGA/J1THCx/BaLeZyi1KALD/sVuPBNWfd0Ly5UiUEiXCYffs8wiw8PoTGrGVpuQjqe6IlCS/AnwncFTLBROCJwX+WGTKgyGe5S270ZaPRsljHtt4yT+ADzGYRqrne/Qn8PlnR32mTHJKbMls2dKfqAxjiEmDOVkjoC31Q24ga5HPB/dHWh9+Z6GOshP6Z6LqzrVO6XrJ56ZGAEq+KVE/0ZSUEjARLhhpkehPKYGU31nnzxxLANCOlnKgQKZv1zJwjWWmHr/GZm1XMRGAneOJ5yq7ukguNSIB0DoJAB9OQoYgKjBu0guz6EVe+6XZui4CgDc8OK1D2P1gX0+C9zi55r34DHZRtrvkjBeFfeJPga9CEtTzaBvY/eTCR3roiOhT9mOF3RgTBDsgzARjQjlrBID2lNJWl+zVqPkjjUKLg+eqxhW/BTIBsqCAIdE1i8SSQ1TRLOXJbVIbIWbLahui/pb8REoEgDYy5q0+DHyTMaNhTvOCIx0OvF5K7wK7ddT/uUNefu9YAlAL/btjJUPlIvNm6vFbpI0bf48IwM4hJJQOR51IiEknhKtF1kEAsKXysWd3Omaxj9q7LgKAk0/JSaoFt1oZb3tlAcG72QthV/k5BjiUncQVwpuf35Fo5413NrZYpLS7qsXb8zx2RJEz5FgchggAJIYIhehdJgafxSQJCyIq9MifhEWYUNfdEMK9mDf8oWmD3Ebe7FHbGEciJfJFjvr+sKaOgB/+I15KBGCR8GG84jGXeMHLH2LgyQTPIK2xl6GDksYSgNoZKdjsSyHUY4diN8ZvbBu3orwIwM5hxLYHk40Er+raAUH5PasmAHxw2HG2pnkdmpzrIgCEc0XhU0PtabnufTAgQezM/ZkNuSMbC71PqcuCn4cw4ThIhEcumA1e0v+AHZkPqZfS4U0k70FN6jUGLX2MygwRAO4paa5YRLCXJyklikHd2qIWX7QPi9yHkyoEihDQobZ5J1EiJFgs1yEQjUizUCIAjE3JsbjUPsgYGSYjwWk1vwbJY05HMuR3M5YARD4z6bm1HBpjx2E3xm9sG7eivAjAzmEkB3spBhqbc8k84CcDLL1mYyf+ODoMJXICZIzwTaglZ8EeSggd6sbchstuyu9+aeu6CADpRnP1+SpfEp9wp7TwseNN2eei/Algnx+AQ2bE57uGEllB6BTCmBCClQu7S+z/3pEMh0O8oKPQS+4naoPFlsUCp658J4dDX5RKtoUAlLLIoZGBkCQpeYp7rckqx23Zupj/aN9Qf5dIFVENRIYkwSy2qlwCUfshnd73o0QAxh7ylZ5XItM40aHyT8KGJXJKbDnPYSwBYAzSe+FxwayEw+EqZDfGbxXt3rg6RAB2DlmNecP8cVKL4sHHDnzJVh4RgFqKUD46OCuVkq1M7QRIXHwpHS/e5y2HHY3BEo0MakkvqI9ZANjFs3jkQkhlHqkAWcPJMBc8qrHfI1HGPHb4ka8DDoSRjZZ6MFdANnKVfP7MRZwA0/1oQ9jxesc6CAb9S7thMu55T21ICc5569oxjxnPWll2s2jBom8WRAzCnRJMgQckN5IWb/VF2lwiALXY+NpzSrkuGMNc3V8K6WzRWI4lAJxv4dNepz4MHcY1BtPdGL8x7duasiIAO4cShy8Wjih5CCWHEqy0TowxBIAdBLvDSAibi+LhU1niaqPEHOvSAJSSANEeb49uxapWrpRpLh3tG2Vny+37qW60Jz6tLmSPxCSQFp/WlwOd+BjmgmMfnvTR7p966H8Ui53q4DlRvvoWDQB1lMxXKesjuyrCIf0731r/KsYLRz80VK0Ocf6ZEIBSPgHMZNjnk5QO58FnwGd0XEXfVk0AMIFECb5oK1EfifDxvYqcSodi8qlnLAEgsiQ6TIy6Vq1Fmnr8VjEHNq4OEYCDDhnq31IsPmd+Y4/0O8axAz+GALBoRJnl0ERER7nmbYl2fFxfFwHA3nynAhirOF/eV82CwsLpz5xHTYr3vw879B7+qb4o5hjNCgtKdIRwFBJKmGPkjc4zcC4lZK0kLPwl7UjrAk2UQZRoJu1ASzkaVum8lfqHKYMFDHMQC1H6F5KFXb92LHPtXYrMMak8mg7OwkhScoyDgNC+oTwAY9/pVRMAnk+IY3RCZUpjXArpbHU8HEsAsPOX1Py8b1HehbE47tb4LdrOjb5PBOCgw1dLy0ppVLmof5eJ/y4lHPImANSafyzMMK8K9MWw/eMbEI3xughAzVxRiktf9gVigcS5LRd+44PEwpsLcd1RnoIovSk7agiAz17Ibh5zhj/KFh8Ff1BSevbjKsSIMsTFY66JpJUAcC+JqnKbP7+RZhXTACTHOzvSF8wlpTm26NjUwsUgv/4MhtbnQBwuHhRG9Y9jXu7/UjPHjMnp0dq2dRAAMvvlES2pLQf24aX8G2VuLCUr8n0ZSwBqtnm0aC0OwGguqMcLCajyTIdTj1/rOG9VORGAeDj5kNc+UizgHDAz1qbNosxiwL2ReALAQpPHvuf35M5uUV1kSisl5mD3UwslLCUC4oOBra8kqCZpV3QSHrsZEqLUhFA/QsHQbqBO51/+UAeWJDoUh0yHLHio6nMhxPMVQUUsginsL11mjMHem1DI1R6ZZEi4EtVNfTgZRgmZuIb6Fq/uKEc611n0PMEpYYGzoj9siLKozfF78LHl3iFyVR+3oWO1FzlwiBMO2dlG6u5IrV/LWY+mKgqzy/sP5mjY0hxMc7IUU78OAlBKrc38xlMe9b83G0FMuc9nv4zGdiwBoI5Sgh6uDSU8wnehFGrqzWpTj9+q5v5G1SMCEA8XccWoc2ue/CwOOKDxEc0PsfA1kgSEDzCqVjxlo8Nb0j2eALCQslhHCyq7HghFZI5AQwGJie5Lz8KjupRKlf5EHtdDWgfqrh1chIaAXUtJSju80qJLPex4oxTNpPvNdyTYnbETlwgV3vv5ka1gAw74DORS2l2VzifgXjy6UYX7UxC5Vout5noLcUrtwxQCkfFjhyYk2ikyL6NcCqv4iNWSQjEWj+77jlltSNj1k7HRj0W6j7p8HvzaYTJEcWAyKYXPgR/mo8ifg+fwPC/rIAA8o+Tkh6kt8v4vOahGGC9CANCgkfEzEkIeIU4lH4/S2RW8F7yrecju1OM3NAe38roIQHlYcZ6KTpbzd6B25IAMQuDYJbBgs3PHkRCPa3wGagtxqg+1PB9pn4u9dG4797Ew4uWedsioQQnTIZFI2uFH595zLx9VUtxGgi219LEdWsRr6UJpJ/f7dKbs6vBaLnkY13LuQ6jQxETJbfK+DZEXzAPpWNbay84uJjq/vnRiYKqLxEH4JqSPI+VZ/FNYVWmcUM+jMq3lvc/bG/kzRHWz+OEMt6hD3tAHkbnPbq829zFPQBQgcEReQAbYwWKjZ4fLIg2ZreWY5/1DexId0FM6w4G2Q8rQxPmjlvG3wc6Ng60X2od2I9L8rYsAlL5DENkonTJ+AaQrbpFFCABjAzkqOUqzIYIk5CZSwiYhTaX3iwRrPlqH9k85fi14bV0ZEYD6kOLxiu163YIqjxcgygHOi8OusySo+oj3hjHjMJRnKWNHDbuOQtZ4iTkrHXUiWoQ8l3jtUCQWDNoJW+dZ/OvVqbVjlekHhIk60jGgqNRT7L7vJ3URulcTTmks5ctP9w2pfSFfNe0E9YAVH77Solly2kptwAmRVLKolvE1yZMYcaogUSY+sRH3koMi7bpYLGvqXUwotSNnU1t8PPk65njNa3xVz+PQnuhoaOpHIwIJKdmmUedDRpPzJofpYMop5RvAyQ3fkkjWRQBY5NHqtKRKRrPB3Goli4sQAPoOceJ0wpJATvBdYZ7SHr4/JcIAmWKTlDtwpnqnHL9VzceNqkcEYHi42JWyOx2Tv3241v8vwW4DZlzKL8DCiDp7bPpfHNjIa8BHKz+yNmobOfWJO05SikGO7o3YO2YPFqFcpT4Gk1SWnTaq9SE1MWPkw/L880oHqaRykBmIWO2dqJ2sRj2QuJRBcEx/IURESbDQc1RtTVqiKT7T7WKxmdeEPAfsutcttciQZZ+NbwUe8bUDjCDFqNGHNERDbSkdNZ3uWxcBoP5aeG3eblLxYmpslUUJAPWvYnPEBgBNZO2QtanGrxWzrSonAtA2nGThIwuWP2q27e64FPH7ZPQqJfHJ72o1R6R7CB1kR8wiTAgW6tHaWHsCgPqV3SoL+ZCU1HeYQdglRBkPh+rkOloIfCZwBhySoV0vCwTt4YNTE3bntTHGqZJ0qDWJkg/VyqN5wWwCAWwZ5xYCsF/XX46gLQkJm0qnXg5hvch1FiU0GFGeg0XqY6eL+WT/xpsxEWAui05NbKkC89Dtg8iP/N51EgA0YC1qfUIs0Ya1yjIEgGfgDwHxbjFx+jYRDQBhHjoinPumGL9WzLaqnAhA+3AyyZmwHMaz6McTuyvJeXD2i2yWtdaw08GzP1IR5/fxcSfci7CcJENs3RMA7oNA4Dw2tHMqEQDqQGuBdgNP/aGcBamtaC74sHM6nQ+1K+GDdgb1fImwcDZDKUNhXieLJotnSbBJ4+tRE1S1OGcxT2rvF2YEQv84HjcRE+4d0gK0EACc1/jAlpxYSXkdnW/Q/jaML8niT1/RSC26EEOSMNMwP8ZmLsSP4t6dOp2+15x7857xjjJ3vV9O1Pt1EgDeQbRTUaro1BawAdcxxzkvSwB4Nk64kLHWNOn4SEGi2fwMEfIc53WP3/gZvQV3iAAsNoiE2WDXSse8kjUOWx0fFj7sOLuxILHgo2blaFYW5rGLvm8dLwFOY+wY2dnzUcWOiQ2fRY7dZ+m8bsLQuBd7Gx8S1Oo4QGGLx3EnUgcTZYC3MZ69mCJYaLHZ8QfBoE9EG5TOIk/t53kQCtR9xGDTD/CiPjztCR1E3U9d/C0Sl16LPmhJi0pba4lO+AC3nlBHXWgSWOzwtAe7FHUBzmh/WPyj+QBWmDTwScBJL2UYRDuBTwc26CGTCM8vZZDE2ZR+1LISLvZWtN+FWpe5AKHCTITDKYtcSuiEDZs/tD9EZ4ATZhK0ZVEkRfuT/6/vl+ufz7uAbRrtEAsnmDCv8eVAezXmeeskAPQPol1LJgV5hWCNkVUQgPQ8dum84zhP8t0AVwg57zI+DMxf5j0Ebpl06usavzG4bU1ZEYCtGUp1RAj8GwEiI1iQIq3LUFZCwSgEhMBMEBABmMlAq5uzQqDmjIg2Z9FUvLMCUZ0VAtuOgAjAto+w+jc3BDAZENaGetsLWdyi3+eGkforBITAgJOSABICQmDzECC+vxT2iXMoGfUkQkAICIGql7LgEQJCYO8igPYuT0iEBzj51EvnP+BIR0a91siKvdtztUwICIGVICATwEpgVCVCYHIE2Onj9U3YJJEDRFbU3mc8tMnOJhECQkAI/AsBEQBNBCGwmQgMHSKU94qYf+LfJUJACAiBfyMgAqDJIAQ2E4FWAkDsNUdbE/8vEQJCQAiIAGgOCIENR6CFAJBxkhS2pM6VCAEhIAR2ICANgCaEENhMBMjsSJZGnP/IoMdR0KRWJasih9+QMZBDgSRCQAgIgRABEQBNDCEgBISAEBACM0RABGCGg64uCwEhIASEgBAQAdAcEAJCQAgIASEwQwREAGY46OqyEBACQkAICAERAM0BISAEhIAQEAIzREAEYIaDri4LASEgBISAEBAB0BwQAkJACAgBITBDBEQAZjjo6rIQEAJCQAgIAREAzQEhIASEgBAQAjNEQARghoOuLgsBISAEhIAQEAHQHBACQkAICAEhMEMERABmOOjqshAoIPAEM9svu/YSM7uu0BICQmA7ERAB2M5xVa+EwCIIvN/MzpfdeDcze9QiFekeISAE9j4CIgB7f4zUQiEwBQIH704X/HW34B8he9jFzOydUzxczxACQmB6BEQApsdcTxQCexGB05jZl1zDjmpmv9qLjVWbhIAQWB4BEYDlMVQNQmAbEDik2/3/s9cIbEPf1AchIAQCBEQANC2EgBAQAkJACMwQARGAGQ66uiwEhIAQEAJCQARAc0AICAEhIASEwAwREAGY4aCry0JACAgBISAERAA0B4TAOATeZGaXzm65vJm9of//IczsSmZ2NTM7u5kd38wO03vSf9nM3mJmTzOzn4175L9Kn9zMrmdmFzGzU5vZ0fo6fmJmnzSzl5rZy8zs71nd/P/q2f9va2ZPDp59czN7evb7583sDIU2rrv/fJM+a2anz57/JDO73QjM6DN9z+WeZvbwEXWoqBDYegREALZ+iNXBFSPw9X4xTtWezsy+aGZnNbPnuYUrevQvzew6PRloaRoL/WPM7AZmRqx+TT5nZtfu20M5iMYxshvObGafCSpggb1N9vsLzOyGhQdN0X/6QBbCJH8wsxOa2S8aADujmX3QzA6flYV03arhXhURArNCQARgVsOt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aBsH3mDPj4SdP1oCnP2S/KOPGIhy+u9+L9UCISAE9hQCIgB7ajjUmBkjQErf67r+E/L37P7oW9LiclDOifskPhx8c2hXfmyWwhnDra4LASEgAqA5IAT2BgIkwnmvmZ15geaQH+A+HUF42AL36hYhIARmioAIwEwHXt3ekwgc3swe0x1wc1MzIw1vi5D7nlS++ZHFLfepjBAQAjNHQARg5hNA3d+TCJy0PxaYdLb7mtkxei9/8v6Txhevfxb813bHAHNcrkQICAEhMBoBEYDRkOkGISAEhIAQEAKbj4AIwOaPoXogBISAEBACQmA0AiIAoyHTDUJACAgBISAENh8BEYDNH0P1QAgIASEgBITAaAREAEZDphuEgBAQAkJACGw+AiIAmz+G6oEQEAJCQAgIgdEIiACMhkw3CAEhIASEgBDYfAREADZ/DNUDISAEhIAQEAKjERABGA2ZbhACQkAICAEhsPkIiABs/hiqB0JACAgBISAERiMgAjAaMt0gBISAEBACQmDzERAB2PwxVA+EgBAQAkJACIxGQARgNGS6QQgIASEgBITA5iMgArD5Y6geCAEhIASEgBAYjYAIwGjIdIMQEAJCQAgIgc1HQARg88dQPRACQkAICAEhMBoBEYDRkOkGISAEhIAQEAKbj4AIwOaPoXogBISAEBACQmA0Av8LQdNQ+dOiFboAAAAASUVORK5CYII="/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-120"><g><rect x="9.5" y="189" width="130" height="40" rx="6" ry="6" fill="#e6e6e6" stroke="#000000" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 128px; height: 1px; padding-top: 209px; margin-left: 11px;"><div data-drawio-colors="color: #000000; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><b>Storage Service</b><div><i>seaweedfs</i></div></div></div></div></foreignObject><image x="11" y="195" width="128" height="32" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-121"><g><path d="M 75 264.63 L 75 250 L 74.65 235.37" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 75 269.88 L 71.5 262.88 L 75 264.63 L 78.5 262.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 74.53 230.12 L 78.19 237.03 L 74.65 235.37 L 71.19 237.2 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-122"><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 251px; margin-left: 75px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">S3</div></div></div></foreignObject><image x="68.5" y="245" width="13" height="15.75" xlink:href="data:image/png;base64,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"/></switch></g></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-123"><g><rect x="10" y="271" width="130" height="40" rx="6" ry="6" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 128px; height: 1px; padding-top: 291px; margin-left: 11px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; overflow-wrap: normal;">Analyse Service</div></div></div></foreignObject><image x="11" y="284.5" width="128" height="17" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-124"><g><rect x="10" y="107" width="130" height="40" rx="6" ry="6" fill="#e6e6e6" stroke="#000000" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 128px; height: 1px; padding-top: 127px; margin-left: 11px;"><div data-drawio-colors="color: #000000; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><b>Upload Service</b><div><i>tusd</i></div></div></div></div></foreignObject><image x="11" y="113" width="128" height="32" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-125"><g><path d="M 455 153.37 L 455 180.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 455 148.12 L 458.5 155.12 L 455 153.37 L 451.5 155.12 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 455 185.88 L 451.5 178.88 L 455 180.63 L 458.5 178.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-126"><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 167px; margin-left: 457px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">HTTP</div></div></div></foreignObject><image x="442.5" y="161" width="29" height="15.75" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHQAAAA/CAYAAAAxBeyIAAAAAXNSR0IArs4c6QAAA/xJREFUeF7tm78vNEEYx78rEoUG0VGJHxGJSIiIQuFHkKAglCRErVKQUChIUPgDRChPUIqCwu9EQSHRiEgkNKIhUQg5mXvf2/f23tubW7Nr5jbf7dzMPM8z388882uXFY1Go+ATGgUsAg0Ny1hHCDRcPAk0ZDwJlEDDpkDI+sM1lEBDpkDIusMMDTPQ1dVVjI+P213s7OzE3t6eUpeLi4vx8vJi27i6ukJdXZ399/7+Pjo6OpR8yBqPjIxgfX0dv+krMabS0lI8Pj7KwnSU5+fno6CgAKJtY2MjWltb0dPTg9zc3LR2HBlKoJ40T1k5PnhUgaYyLuDOzs46ki65HoGqM3RYCBJo3FFfXx82NzeRl5f3X/TagT49PWF3dzcjWaenp/H8/GzXnZqaQllZmbRtZWUlWlpa8Ju+0mXo/Pw8KioqXOP++vrC6+sr7u/vcXZ2hqOjIyRfuQ8MDGBra8s8oFIaCRXKy8txd3dn/3J+fo6mpiYvJjKu66ev5DXUa9y3t7exafbw8NARfyQSwdDQkOM37RmascIA/BRZ5tdPX6pARawfHx9ob2/H8fGxHXp1dTVubm4IVAZTlJsGVMR0fX2N2tpaR/gie0Ws8YcZ6kLXRKAi1JqaGkdWbmxsYHh4mEBlWWoq0MHBQcdmaHFxEZOTkwSarUDHxsawtrZmhz8zM4O5uTkCzVag4riys7Njh7+ysoKJiQkCzVagyUvB9vY2+vv7CTQbgV5eXqK+vt4OPScnJ3bRUlRUlBlQcZuRuIOSiZCqfGFhAe/v73ZR8uW8F5t+blRkfv305dc5tK2tDScnJ3boqV6epD22yDr9k3ICBbzeFD08PGB0dBQHBwf/MtGycHFxgYaGhswvFn4CTNaGQIHl5WVUVVW5SiXubd/e3iBAnp6exl5hfn5+OuqLna3Y4SY/zFANFwuyQS8rF+dOcf5M9fCmKIuAiqxeWlpCb2+vK3MCNRSoeNdZWFiIkpISNDc3o6urC93d3bAsK20CE6gGoF43RbIpOLGcQAnUy3gBZB+JebHm59lQ5tdPX36cQ2XxxsuZoczQTMfKn3rMUMQ+xUz8jJNr6N8x5Oc0KBuWfvoi0F+YBglUpoBLOadcTrmuQ8fPaVA2Pv30xSmXU65svPHqz6tCzFCuoa5jRtuU63UUs755CvAffs1johQRgSrJZ15jAjWPiVJEBKokn3mNCdQ8JkoREaiSfOY1JlDzmChFRKBK8pnXmEDNY6IUEYEqyWdeYwI1j4lSROm/2lUyzcY6FCBQHaoH6JNAAxRXh2kC1aF6gD4JNEBxdZgmUB2qB+iTQAMUV4dpAtWheoA+CTRAcXWYJlAdqgfok0ADFFeH6W97Qt2suZ3FFgAAAABJRU5ErkJggg=="/></switch></g></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-127"><g><path d="M 236.37 41 L 265 41 L 265 100.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 231.12 41 L 238.12 37.5 L 236.37 41 L 238.12 44.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 265 105.88 L 261.5 98.88 L 265 100.63 L 268.5 98.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-128"><g><ellipse cx="215" cy="7.5" rx="7.5" ry="7.5" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><path d="M 215 15 L 215 40 M 215 20 L 200 20 M 215 20 L 230 20 M 215 40 L 200 60 M 215 40 L 230 60" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 67px; margin-left: 215px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;">Researcher</div></div></div></foreignObject><image x="184" y="67.5" width="62" height="17" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAPgAAABECAYAAACs2fgFAAAAAXNSR0IArs4c6QAAEqFJREFUeF7t3QOQLc2SB/B8y7e2bdu2bdvet36rt7Zt27Zt27bt3f5FdG1k5NeonnNm3pz5KiMm7r3T1V1VWfVPV937xKDBgcGBO8uB+9zZmY2JDQ4MDsQA+NgEgwN3mAMD4Hd4ccfUBgcGwMceGBy4wxwYAL/DizumNjgwAD72wODAHebAAPgdXtwxtcGBAfCxBwYH7jAHBsDv8OLey6f2VxHxKIkHLxcR33Rv48kA+L1txe898x0Aj7hHocsjRsTfnrAH/ici/jEi/i4i/jAifjoifjgivjEi/u2E745XBweOcmAA/BoAvrYIhMZnRMQHRMS/HF2p0X5w4AocGAC/QYC39fndiHjliPi5KyzYeGVw4AgHBsA7Af6jEfErnZx9iIh4hIh4soh48oh40IX3/joiXjAifqnzm6PZ4MBVODAA3gnwt4uIT7oCh0UwXzsi3iciHq28//OTX/4s07P/vsJ3xyuDAz0cGAC/ZoC3RQDu74iIZyyr8oYR8fk9KzXaDA5cgQMD4DcEcGvzJLNJft+0UN8cES97hYUbrwwO9HBgAPwGAW5BvnIC+aumlfmniHi4npVKbZ49Il4qIl44Ih53Nv35/X8ZEX8REeIF3z5bDP9+8NuaP8wsdF48Ip4uIh5/HuNDRsQ/R4RN8xtzP18fEVyNq5B0JOH2ErNlw8p55DnFqI/fjojvnAszfvMqHczvmA9+6edpJ4vpieb54Nk/RMTfzHOQyvzimYc93T3sPNbW9u8jwpyQuMtbTnN4vYh46rm//Hzt+w8eES85j/e5IuIx5kIV6VXrK+Vqbb+sMxNTAY4P3zZ3/iBzsNd+5Co+VkTgSUvv/tBsXf5MDzMW2jxYRNhD+P4881weNSL+a57LH09xqO+LiG+d2v3IgT4+auL7O6f295v4/nHzv59qSkW/R0S8UEQ8ZkTg5/1qoctSHvyqPngd97tMAPrI8ksAB/Q9eraI+PB58HttPf+9iHivKdD3JT2Np/SdBccs8QJBwl76ngkUbx0Rv975AgvmnaYN+m6d/agr+MJ5LjZFL5mPfu4/C46e9/5jEpifHBHv2VGzAMQ2a6P/nAHi91+3YJntAfzl570hMLtHUq428mdGxP9uNK4Af5GIsF5PM++Lp9/raOb9W0TEv3a0bU1eIyI+KCKetPOdH5wwABs/0dHed+3rRv7+IXPQmrDIFrI2NwrwN58k5aeXSTx2RPzpzsTeYNLWnzUxjVQ8Sp82Scy3iQhAWSPfpRVe5ejH5/YE1EtHhIXaIkFHpZLPeYV+WCc0Qo/FQBN97TymK3QVPz5bSHv1CkCd18Tf3zEiaJlKWwB/vwmoD7jCQAm+N9oI1FaAP+8M1O9O1kZPt3gptbtHhJtgNOvlKBGWbzwLlK13ARrIG/n7R0TEr011JrBU6UYB/t6T+faBZQQkzpYpbQE/p7xD03xBRHzLrKltNCaWBXyTSbI/TmlPK73tBtdogw8tz2nkL58BBVz6oNlpGKYeU5KWbCT19xQR4c8lYiqT0EzWTL8wzwWovPvwk7B5yqlO4BUj4hWKC8V8ZMn81s7u+ZSIeKvS5k9mIcbkNB8bisB55tmU5u5k+qL591tdEWzm1YhZ+Mul/hvI8ImlyAWpVDes59wG7o+x4gkr75kigmZ8pPKBT5zav/3KICvAX2zeS483a34aj8mv4pI5CyAE9YsuuK7W4ht2+P55EUEZZcJryok5TpERvk8wVXcai7YPnRqzRl5z2iNfsdFPtYI/enYb8/7l0hCo9uv9b9JE/65JyzGTGil6eeKNyTBxFMTkTSQfz5zjoy4RgUGKAnomPvv3LrxgYS1C8x81+YTZXN/S+vw2kt1mafRhs0m8NC6WBFOvkcVkPnNZ1vrhu31NRDx6es9GMZc105RwALIsfAQzX33Db32oyZwE6KylfB/4twqSbCICqRFBiQc0PzPfhtcGWUMxjExAS7BZg0Y2Nw24VC5tjcQJgDATnxNfKlWAW39tuW+vNrkRP7W0UJNQf6U5XpRrOCiTl1lp79eA+aXluZiTfah0e4kIFHtIXKmRMfOl/blE3MiPSQ8+deYHocEywfefnPcHbN/3pgD+rLMGy/3xoZjta0SKA3MjPqhU29rk83fqu784gWXJ53r+adG/P734Z3Pwric/D+SY2eZk4whiVQIUAaJMFqJaDUt8sPgCPhkEXAnAXyJxCv59I6ASKKQVt4gm+f1JOAoENfItoF0j38waVfDxCWd/ULBzjwBOwVMjIKXZsm9fv0GA/+xs5bRngpHcl0oV4J4T5tZjL55RrSB8JMyWhLEA7B8UQcw6EETdUhLGQ2hxu6xRoy2rhLXy8aktnrMqxT3si3v0dxMAN3ggsviZgHXNpySRfqdoIhqGxOshmtX72UcEFoDM9LrF72Fl2GS9pLYeATeA2LSVyZ89+1ftm7Qi4bC3+K29uEUWhFva5INn0ND6fgSVaKQeqpv6xyYTVjR7jZYAJOCTg0Br76p0tDkzcT/WtOrWmuGjuVb3aGl8NPdXdTDjOSY3zPwzsY6WgqmyBVzGRlxOgn4vttTav1YJBrNeuJxLritXkwDIxEKArUUhfp0AJ/H4Ge+/4DvxS95sg9Gi2Q08mgErk30ralo/R6rxnRotScZqWtl0fOlzEeluwZjBjY4W+BCEtFYj1oUNIHW0R9a3l2c1CEorEbRrVAF0ZFz2xPumDwMOAPUQX54gBuj2I1VU04l1fFxCe6hHsLJoqkvxApN79AMLA2Qac5sacU3EjnqJEmI55rPra1baEsC5lO+w1lkPwJlOPdFbfRhsq0W3MW3wSvwuvnhlYG7HxBHIakS7iIYfIYEm7zWivbO/4/e0Rk1P2Ojch3NQ1QTAJhjFVOwla0QbyAs34g/S5OckOWF+YyOaIfvYta8KIK7E83UOSHArm9VXWd+9rur4jvZh/vL9jbiLjj1n4qeLM+Q4kXhH5uPeOD0X0PVeI7GZ7Gq13y8BXFCQkFmkHoD3DLC3Dd+YSbMWeGjfIZlz1JW2p/WPEPMyFxGILorIZh/P/AXusvYAQiaXCCXf/RSqPhPfr0ase75fASEjwRw/J4ncZxeIAM4bvPZVAfSxc+69Z0z1XRqIJjon1T6OCm5COJ+hWDLvxXWq8uN+7GU66jwFXLk3jdZcxSWAU6iKlh6oAOfPkEprwaE8OAOWEsrErztS8eNdJk/1t5aYz7xS4ZQDWa1vrgFrAsPFEY5ehmHTyw03YkZuBRbX1kn1Ui7rFU0WP9gjwU0SXlWeudPIhNySZSWFkysLjwKchZUtprWxGUOLrrc2PWmovbnW5xXgLJSvPvARZnO2mpYAbtxcwUysq70agjoMFi2h3WhNEVSAc9NyluUe07tuDa6AQQoGUHqJ3ydodR20Fshhfjn4ktNltX++G1+YNmWJ9FQefe40Fz73uWmvjt9mpuF7KsPWxnYU4IJFCob2SNBVQDLTWhpz71tbz0+tRe8BuBgTn/vctMb7CvDd2EUPwHtLVZnUOsypFppRYcgRWjJ7jry/1baVKy61sfEE9mxU2myP5OKlLOS4FcIsEYulN4q9119+rmpOiq+S/DdX5kiQZ63fowDv1cKsCQU+mVT3ic2ck24C4NUFO+f4xbNqurYCnMKR9lulcwJcJ0uVZ3xuWryXVHsp1rgO6tmETHsakE8qcpoj4EtjItSk8JYuxVC4wbQ7N60trEKTdy+diTmoyWd1uGSDZmJC1nzzqT54762lSwBX1HPUBdvj6U0A3DkElZLXQUu+dQW4+gpu2I0BnMCQSlA22kjATHVOT1rHO0pN/6iMeC1FcR2Mzd9UWGHz8WNpf/nrXCXW2vLNRcxrqkY0/k3TB+XJc0rlnOPnYxOMOZYg1SUb8asdHd0UwJdMdLUH4hznpJsA+OsU5cWNo3l7U5NH5/tAB7gBO5ZIw+QiE74Z07eHpBzqCbOlFEXPt87dhvshR+mkVvVvCTaCKJPAovrhRuqrCYnrIHX+OVBjs1mLHnAbj1rv7EMfNdF7NfhSELXXfz/Ct5sAuIBavWtdEHEvS3RkHrntrQC4ATnh8q5lFr0bwGsORyjmaMTXqRU8V2XSOd6jJUWMs3b2XfGDnFqrxSOsmRyjOMdY2jeYuLnyzOGIXOiz1xfTnonf6LoA7vs1DSoYmwub9sba8/wmAE7I1+q2ugd6xtrb5tYAnBamOfJhDGa3s7irObs0y1pLLsJ9HdHoXsYutWOhWNx8YIZP5gBAIwcq6qUByhivI0vAHM/8VilWT+9tzbceBrpOgLvCK5cESzUdCUaKk2RXhMashVM3AXAuqRLRnH0Rh7qOyLq1uzUANxgLVvPeIs71KOPSpqvahMR3+sZR0esgfrXI+dH/nMFR1hyxrqAiBGyAnF+W084ngs41H3GAvNGOFHaIkQjA5fjCdQKctlaO3IhLxrLpvYXnz0v+ly9cL/e4CYAbf626VO2WD0mda31vHcANiH+Sj9kJPjhBtFTTmxkh0CZXmo/sMYcd3OglpZCqg2gLuWsmbE5nqTmXApRmeIbZ5K5uxV5fNlWOLSylFOtRUek1lkzvZm58BDhz8eMMcyVWQa4dJyS5SntECCniee7SkDBdKohpzU4BEN67pCCTY6L1QpClsSs3rik1VpRa80ynjM93evLg2tXzDLITMgV1flvrwEURzG3rW9OI7d1bpcENijkqsptTTQ50ANSetqw5ZFpcgKoWSSwxTk5e9ZzIcqMKvhrNBSDjWjtrXvvhhijgyZVESwUbvlnPVSuDzcG3rcU37lzGqS4dkGvuXc2BO8AarR2jzH0xMX3bxrGh1cln2iqDPBVAhHyuXde/9RV/WSPjBQJZjUZrNQGnjq8X4Cw/7lGuenPHnaxLjxCX5lLHn4Xpmh9/6wBuEZx9rnXTW5cjtIVzEytg5HrovcP63hU5dvjen40sADO0lhBW88r3mXt7OVkb35VBAoeNAI8PvHSWnF9er/JxtREzdU3Q8TFpYeZsrlewyEu516U776S+xDOWiB+r5t4FCoSFgqSaqto61HIqgFQVOjeerTTKwKGLpZoC0WnWUM3GSAOy0CqdOr5egOvXmB0YyUTAqnTbOjbKjWWV5nP1yqvXaiduJcBJOAX5+UAHM4aplY9BLm1CgTXlnpmkf/g5fmhQARY+ru9bbDXb2Ze0eZnrS7d+KKpxyixfnaMvAKcpBApZDr5BY9P6xq2wpZa1SjOtXbfj+/qpVzYRPMx8/fErjVusQR9Mv3pc05jMcSnPymph3WSBiM80tNNNgpzy+u3aKZuvxQZaXECtQo7ys2YIJn9axxwxPhVA+Fx9cb/Da4KXhnfgA99pdunJemUTk37tDrRTx3cE4Ma9VJYstiD1COwsExodf2lo8yHkMqlB5zKunTa8lQA3AVfluHwgk+iy4pCtGzy0f/25/HLpMMiKcvr/X9PYNHI9EJDfo4VJ372KtbW+gI2mrTfG1vY0JqG0dYnC1nxoVxp565jtVWqjnaV2FRBaulesjanWv58KoPbdpeq7vXX1nGC0N9Zu3zl1fEcBzhKRyu0JIi/Nj3CmiOpFGLntrQW4QTJp6wkoVwK5GmiPSHAbIftee+/QAk5ybTGsfYM57+TXke97lwuh6GXpvrel8dGgxuSsb9VGa/MhzQULbZ6eywpEz2ntrQCZvpzoMg7/62sjMQvlj0v31V8XwPVNm9kH3LI9kpXg9u0F5G4a4G3czGvpyd6LQ7hozHRz2ksh32qAC0KILGbT1uSYK72X+wM6X5FFwHx1XpcJR1MDgu8LcDjXfCSK2RaHCc3Ed/jBAgk6+b5IM3PL5vJd1geroOeKoaUNy5/k38oFm5N50PCsAYssIsyt4VsC1l5AsvbBzGe6CvQwyfGc6csNEKEVkHPkdGlDiQC7ccVhFuPkokih2YS50u1UANUxs9CsrR9WjuAlnjBr8398IL7Scxzz1PEd1eB5PrQ5ZUEjK9u2j6xx20dMcfEGVq191HsByMkA35Oe4/ngwODABXGgnia7oKGPoQ4ODA7scWAAfI9D4/ngwAVzYAD8ghdvDH1wYI8DA+B7HBrPBwcumAMD4Be8eGPogwN7HBgA3+PQeD44cMEcGAC/4MUbQx8c2OPAAPgeh8bzwYEL5sAA+AUv3hj64MAeBwbA9zg0ng8OXDAHBsAvePHG0AcH9jgwAL7HofF8cOCCOTAAfsGLN4Y+OLDHgQHwPQ6N54MDF8yBAfALXrwx9MGBPQ4MgO9xaDwfHLhgDgyAX/DijaEPDuxxYAB8j0Pj+eDABXNgAPyCF28MfXBgjwMD4HscGs8HBy6YAwPgF7x4Y+iDA3scGADf49B4PjhwwRwYAL/gxRtDHxzY48D/AbTWH0p48Qc9AAAAAElFTkSuQmCC"/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-129"><g><ellipse cx="185" cy="524.5" rx="7.5" ry="7.5" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><path d="M 185 532 L 185 557 M 185 537 L 170 537 M 185 537 L 200 537 M 185 557 L 170 577 M 185 557 L 200 577" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 584px; margin-left: 185px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;">Database<div>Engineer</div></div></div></div></foreignObject><image x="159.5" y="584.5" width="51" height="32" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-130"><g><rect x="220" y="481" width="310" height="14" fill="rgb(255, 255, 255)" stroke="none" pointer-events="all"/></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-131"><g><path d="M 455 481.37 L 455 508.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 455 476.12 L 458.5 483.12 L 455 481.37 L 451.5 483.12 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 455 513.88 L 451.5 506.88 L 455 508.63 L 458.5 506.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-132"><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 496px; margin-left: 456px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">HTTP</div></div></div></foreignObject><image x="441.5" y="490" width="29" height="15.75" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHQAAAA/CAYAAAAxBeyIAAAAAXNSR0IArs4c6QAAA/xJREFUeF7tm78vNEEYx78rEoUG0VGJHxGJSIiIQuFHkKAglCRErVKQUChIUPgDRChPUIqCwu9EQSHRiEgkNKIhUQg5mXvf2/f23tubW7Nr5jbf7dzMPM8z388882uXFY1Go+ATGgUsAg0Ny1hHCDRcPAk0ZDwJlEDDpkDI+sM1lEBDpkDIusMMDTPQ1dVVjI+P213s7OzE3t6eUpeLi4vx8vJi27i6ukJdXZ399/7+Pjo6OpR8yBqPjIxgfX0dv+krMabS0lI8Pj7KwnSU5+fno6CgAKJtY2MjWltb0dPTg9zc3LR2HBlKoJ40T1k5PnhUgaYyLuDOzs46ki65HoGqM3RYCBJo3FFfXx82NzeRl5f3X/TagT49PWF3dzcjWaenp/H8/GzXnZqaQllZmbRtZWUlWlpa8Ju+0mXo/Pw8KioqXOP++vrC6+sr7u/vcXZ2hqOjIyRfuQ8MDGBra8s8oFIaCRXKy8txd3dn/3J+fo6mpiYvJjKu66ev5DXUa9y3t7exafbw8NARfyQSwdDQkOM37RmascIA/BRZ5tdPX6pARawfHx9ob2/H8fGxHXp1dTVubm4IVAZTlJsGVMR0fX2N2tpaR/gie0Ws8YcZ6kLXRKAi1JqaGkdWbmxsYHh4mEBlWWoq0MHBQcdmaHFxEZOTkwSarUDHxsawtrZmhz8zM4O5uTkCzVag4riys7Njh7+ysoKJiQkCzVagyUvB9vY2+vv7CTQbgV5eXqK+vt4OPScnJ3bRUlRUlBlQcZuRuIOSiZCqfGFhAe/v73ZR8uW8F5t+blRkfv305dc5tK2tDScnJ3boqV6epD22yDr9k3ICBbzeFD08PGB0dBQHBwf/MtGycHFxgYaGhswvFn4CTNaGQIHl5WVUVVW5SiXubd/e3iBAnp6exl5hfn5+OuqLna3Y4SY/zFANFwuyQS8rF+dOcf5M9fCmKIuAiqxeWlpCb2+vK3MCNRSoeNdZWFiIkpISNDc3o6urC93d3bAsK20CE6gGoF43RbIpOLGcQAnUy3gBZB+JebHm59lQ5tdPX36cQ2XxxsuZoczQTMfKn3rMUMQ+xUz8jJNr6N8x5Oc0KBuWfvoi0F+YBglUpoBLOadcTrmuQ8fPaVA2Pv30xSmXU65svPHqz6tCzFCuoa5jRtuU63UUs755CvAffs1johQRgSrJZ15jAjWPiVJEBKokn3mNCdQ8JkoREaiSfOY1JlDzmChFRKBK8pnXmEDNY6IUEYEqyWdeYwI1j4lSROm/2lUyzcY6FCBQHaoH6JNAAxRXh2kC1aF6gD4JNEBxdZgmUB2qB+iTQAMUV4dpAtWheoA+CTRAcXWYJlAdqgfok0ADFFeH6W97Qt2suZ3FFgAAAABJRU5ErkJggg=="/></switch></g></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-133"><g><path d="M 265 481.37 L 265 508.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 265 476.12 L 268.5 483.12 L 265 481.37 L 261.5 483.12 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 265 513.88 L 261.5 506.88 L 265 508.63 L 268.5 506.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 495px; margin-left: 265px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">JDBC</div></div></div></foreignObject><image x="250.5" y="489" width="29" height="15.75" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHQAAAA/CAYAAAAxBeyIAAAAAXNSR0IArs4c6QAACm1JREFUeF7tnAWoFG0Xx881Xrsbu7sTuwsVxU5QTLDF7m4xMRC7CyxssTsudjcGJrZer/fjN3yz3+zszM7uvbvDu/ebAyLuPvOcec7/OX3WsKioqChxKNZIIMwBNNZgqRzEATR24ekAGsvwdAB1AI1tEohl53F8qANoLJNALDuOo6H/b4DeuHFDihYtannsWrVqyeHDhw3XLV++XLp162a5R1hYmCRPnlxSp04tqVKlkmzZsknFihWlUqVKUqZMGfnnn38s9zBa0KFDB1m/fr1Pz8aJE0eSJEkiyZIlU/gXKlRIKleuLI0bN5a0adP6tIcvi65cuSL79u2TCxcuyP379+Xly5fy7ds3iRs3rsI7Xbp0Cu+SJUsqvIsVK+bLttZRrp2AentjAO7Ro4f07dtXMmXK5NPh1EX+AGq2cbx48aRLly4yYcIEyZAhg1/81cV///6V1atXy6xZs+TWrVt+7VG4cGEZPny4tG3bVrh0ZmRpcv8tgKoHQEsHDRqkCBYh+0KBAFTlkyVLFtm/f78gYH/ozp070r59e0EzY0JYi7Vr10qOHDkMt7EE9OPHj7J9+3aPhy9evCjLli1zfe6PyS1RooSMHDnSY09u8KdPn+TDhw/y4sULOX36tFy/fl0iIyM91nKwjRs3CgK2Ij2gCLZp06aGj/EOmL7nz5/LpUuXFDfy48cPt7W5c+eWa9euSeLEia1YK9+zR7NmzeTr168e69OkSSPILnv27JI+fXqJHz++IHM0+OTJk/L69WuPZzD9R44cMTTDloCavfGmTZsU9VfJH0Dr1aun3HJfiMNxcebNmyevXr1yewQfx6H52xvpAZ06daoMGzbMF/by7t07GTBggKxbt85t/ezZs2XgwIGWe1y+fFmJAX79+uW2tkKFCjJ58mSpXr26qQnlcnEZxo8fL2fOnHF7HlCvXr3qcaH/9YCqp0BLevXqpfggLaHt586dkwQJEpgKNyaAqpvWqVPHLegjWMOCeCOsTalSpeTx48euZfi/uXPnSp8+fSwvg7qAhhiXUG/VuAxHjx4VgkmVQgZQ9YWnT5/uoV0EC1OmTAkqoDt37nQz05hKtNcbderUSfF3LmGHhSluonXr1j6DqV1IMDV48GC3Z3fs2KGY85AFlBfv2LGjmwlEOx8+fCiZM2c2FFQgNPTevXuSP39+N00z8u3qArQyb968bv6fCB3XEROqW7euHDp0SNmC9A6Ate4j5DSUg3z58kUJIvCvKmGOJk2aFDRAb9++reSFKpFGEbyZUe/evWXRokWur7lsDx48kIQJE8YET8EnE1M0b95catas6RHphySgSGTMmDEyceJEl3By5cqlaKkRBUJDMW0IUaUaNWoo/suI8HlErFqTzGUziuxjhK7BwyEL6JMnTyRnzpxuR6LikidPHo9jBgLQhg0bKpUdldASs+rXzZs3pUiRIm7vQSXI34JIdMAOWUA5LOkK+aJKlPfatWsXUEDRNooY48aNc+0LWJg+s1LkkiVLlIhcJXwpPtgOCmlAW7VqJVu3bnXJCaGPHTs2RoCS+1EAwAKQllCH1lZ3smbNKseOHRNMvBn179/fLfghiFuzZo0deFrXcs3ewq7CgjcpkMstXLjQtaR79+6ydOlSS0CjI1nKjFSYKCiQsngjfbpilVZF533MnglpDUUbMYcqYW6NuioxreWijYDSpk0bSZo0qaX8GzVqJHv37nWtI3ceMmSI5XOBWBDSgE6bNk0RtEoInMRdTzEFVN0vUaJE0rJlSyW69lZupIJz/Phx12ssWLBASGPsoJAGdNSoUUo9VCWiTm3DQP1cDyjrjIIndX1ERISS61IcIPjZs2eP8m+V6Jdu2LBBmjRpYohRgwYN3GrVdqUsvExIAwowBC0qUTWZMWOGpYb6U5xnM7ovlBZ5Tv2hAT6VjkfVqlU9+FHa27Jli+tzivj4XjsopAFFmHRbVCIgIjCyMrn+AqruR1GdzotK5MGkI/q+7NChQ90uFj519+7dduAZuhpKO4pa5vfv312CAlz6pMECFO0kB9VOG6CJ+FUtrVy5UpluUIn3pGqk7YoEC92Q1VD6qfgqrV97//69YRstEJUilQ9BGMGYSkap0t27d6VAgQJumDE7VLZs2WDh6No32oASTWoDC29Na/2QmD8NbjMJUFelvqoSAQotLiMKJKD6KhDdjwMHDniwZUTk6dOnrs8DWVw4ePCgUACpX7++B9+wiIiIKPwA9Uf+YFbokFsR/qpnz56uZQQCFBuMKNCAhoeHS+nSpZVDqbRr1y5lOi7YgM6fP1/69evnYmNWpNdH4JQJMdWMr8SEcDFoPyXPcuXKKZUx6swqhYWHh0fR9VeJxBnTZTUySaI8c+ZM13Peen2BBPT3799SpUoVZfxRJWqlDGGZTcMFUkMBE1BVMst9ETjgkQKpxNjJqVOnlFHN6FLnzp1l1apVrscZ8yS1Uv1zWGRkZBTzKdre4ubNm4U6qTdCQ7Q1TrPCOHsEClA0kmBDP4ZCVUZ7S/XvHShA//z5I/ny5XMbKSEPHjFihKGomE6cM2eO23f43MWLF3sdxTSTu9G0Bi08rIRLQ/nBL/Ou2oSczjxgmU21MbjEjI1KhO3Pnj0zbQ8FAlAuXNeuXd38JvwBSzvmEUyTSy6q72niprSNby3/z58/KzNF+j4t7gmZ+FJGZD8uElMJ+lzWyCoqQRGjkphdrU8icEFTU6RI4SYj/BfO+M2bN67PrYQaE0BJ6jExaIJ+6o9p+hMnTgglOW8UUw3lHSj3UbTQ/g8GBGbbtm3zyhvAGSgDXC1lzJhRiVWYnGRS3ogAkirV6NGjhfloLVWrVk0IjvSu0RXl6jsXPIwpJpLlBpL3MUrIjC6MVGIUg3FCRkLMSA+o2Vwuz3OpKLPhg7ASVGO0uabKg6ICgZD+wvmiod7mcnke0GihcYE4GymSfqaWNtrZs2dN55i074GPI8V6+/atx+sBCOAULFhQmXLAKjItyEXgsho9U7t2bSWiN7KgLkABDD9kNlZhJCg0g9TBKHzWrvf1ty1er/p/vySgoMTH7bYK3NT9AlWcV/cjCANkbz1R/Vm4oLgMtCq6xNmJntFYs8DKLQ/9+fOnULaix6g1v0YvQOhMcELobEWBAJQDEKjhw/z9GUKgAE2ZMqXSNeEdojvshWZRejx//ryV2FzfE6NQjSJF0U4eGm1gWFh49OiRrFixQmkBkaMSkHAATEL58uWVLkOLFi18Dr/9BZSxTH6Fhlnjl2+YJHhaNZbNJBQdQAlYMOe8A6kBJp6fT0QXSP27IVfqu6RfmFd+8qB2dODLlGDx4sWVFA2+vp492pUin6+Xs9BWCTiA2iru4DNzAA2+jG3l4ABqq7iDz8wBNPgytpWDA6it4g4+MwfQ4MvYVg4OoLaKO/jMHECDL2NbOTiA2iru4DNzAA2+jG3l4ABqq7iDz+x//31G8Hk5HGyQgAOoDUK2k4UDqJ3StoGXA6gNQraThQOondK2gZcDqA1CtpOFA6id0raBlwOoDUK2k4UDqJ3StoGXA6gNQraThQOondK2gdd/AGTpUcp01/CWAAAAAElFTkSuQmCC"/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-134"><g><ellipse cx="357" cy="509.5" rx="7.5" ry="7.5" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><path d="M 357 517 L 357 542 M 357 522 L 342 522 M 357 522 L 372 522 M 357 542 L 342 562 M 357 542 L 372 562" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 569px; margin-left: 357px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;">System<div>Engineer</div></div></div></div></foreignObject><image x="333" y="569.5" width="48" height="32" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-135"><g><path d="M 19.5 523.6 C 19.5 518.85 30.69 515 44.5 515 C 51.13 515 57.49 515.91 62.18 517.52 C 66.87 519.13 69.5 521.32 69.5 523.6 L 69.5 570.4 C 69.5 575.15 58.31 579 44.5 579 C 30.69 579 19.5 575.15 19.5 570.4 Z" fill="#e6e6e6" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 69.5 523.6 C 69.5 528.35 58.31 532.2 44.5 532.2 C 30.69 532.2 19.5 528.35 19.5 523.6" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-136"><g><path d="M 79.5 523.6 C 79.5 518.85 90.69 515 104.5 515 C 111.13 515 117.49 515.91 122.18 517.52 C 126.87 519.13 129.5 521.32 129.5 523.6 L 129.5 570.4 C 129.5 575.15 118.31 579 104.5 579 C 90.69 579 79.5 575.15 79.5 570.4 Z" fill="#e6e6e6" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 129.5 523.6 C 129.5 528.35 118.31 532.2 104.5 532.2 C 90.69 532.2 79.5 528.35 79.5 523.6" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-137"><g><path d="M 49.5 533.6 C 49.5 528.85 60.69 525 74.5 525 C 81.13 525 87.49 525.91 92.18 527.52 C 96.87 529.13 99.5 531.32 99.5 533.6 L 99.5 580.4 C 99.5 585.15 88.31 589 74.5 589 C 60.69 589 49.5 585.15 49.5 580.4 Z" fill="#e6e6e6" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 99.5 533.6 C 99.5 538.35 88.31 542.2 74.5 542.2 C 60.69 542.2 49.5 538.35 49.5 533.6" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-138"><g><rect x="0" y="506" width="150" height="105" rx="6.3" ry="6.3" fill="none" stroke="rgb(0, 0, 0)" stroke-dasharray="3 3" pointer-events="all"/></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-139"><g><path d="M 170 547 L 156.37 547" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/><path d="M 151.12 547 L 158.12 543.5 L 156.37 547 L 158.12 550.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-140"><g><rect x="390" y="271" width="130" height="40" rx="6" ry="6" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 128px; height: 1px; padding-top: 291px; margin-left: 391px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; overflow-wrap: normal;">User Interface</div></div></div></foreignObject><image x="391" y="284.5" width="128" height="17" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAgAAAABECAYAAAD3Lo2pAAAAAXNSR0IArs4c6QAAFYlJREFUeF7tnQXwLTcVxk8p7lCguFPc3d3d3YqUFinFaYFCkeLu0lLc3aW4u7ZIseIFirvdH7M7sy+ck81md+/b+/7fmXnz2neTbPZLsvlyLDuZRAgIASEgBISAENhyCOy05d5YLywEhIAQEAJCQAiYCIAmgRAQAkJACAiBLYiACMAWHHS9shAQAkJACAgBEQDNASEgBISAEBACWxABEYAtOOh6ZSEgBISAEBACIgCaA0JACAgBISAEtiACIgBbcND1ykJACAgBISAERAA0B4SAEBACQkAIbEEERAC24KDrlYWAEChC4OxmtruZXcHMdjOzk5jZf8zsj2b2MzP7vpndpvn/ogZVSAgsCQERgCWNhvoiBITAUhB4iJkdYGbH6unQKc3sV0vptPohBIYgIAIwBK15y57ezI4MHvEFM7tY5ePPZ2ZfC+p+0MyuVtmuqg1H4NNmdsmg2lnM7AfDm1SNGRC4m5m9sLBdEYBCoFRseQiIACxnTEQAljMWc/VkEwnAw5uTcIvJV8zsQnMBtIB2j90Q8VMV9kUEoBAoFVseAiIAyxkTEYDljMVcPdlEAvB1MztvB5AdnQBc3sw+mpkA7zazz5vZX8zsNGa2r3wA5louanduBEQA5ka4vH0RgHKsNrXkphEAz3y0oxOAu6829hcEEwyfgP03dfKp30IgRUAEYDlzQgRgOWMxV082jQA8tjnhdvHY0QnAA83sicEEwPTB+0uEwA6BgAjAcoZRBGA5YzFXTzaNAHzXzM6WgLGjEwC8/w8MJgAq/5/PNTnUrhBYNwIiAOtGPH6eCMByxmKunmwSASDq5HMOECIAc80OtSsE1oyACMCaAc88bukE4CJmdsPGA/w8ZnYyMztRkxjl92b2UzP7hpl9eFXmLWZ21Aho8cQmPJE/lzGzU5vZKVbe6Mcws182z+I5bzezTw14zhfN7MJOeey62HeR460cvB68epebm9mZV+rg45vZn8zshAOeExWtIQBPMbP7OQ1+aOWsdpXk3y+9CiW8k5ldzszO2MSwE6N+uJm9x8xebGa/zbwHp9tdK97zkOa5fVUvZWZXX82RKzX9Y0zBlz4yrp9dhbu+YzXm7zOzv/U11vz+VDPbpwCfO67mDfZ95u5Jm/IXN7O/ZsJkS7qQiwJgHvO+1zazCzTaFNYMc+wPZvabxqTwSTN75QTaBSIXrtU8k+eBL3/A8uhmHjAHX9es1ZL388rMtT5r+6N6lQiIAFQCN0O1pRIAPihPMjMcwkrlH6sP/EGNw9QvSiuZ2c5mdmczI/SMDaxE8Nje28y+XFAY0nBFp9zTmk2WTf4jZgbZ6cr2JACQk0c6feZ9WzJDhjo295v1YMCGs5eZvTYoNxcBgKg8xswgKCVCPoQHmNkbCwqDjeeY96XOOBLTT2x/KnMRgGM2ODOP2YBLhDVz8IoY3L8iqoBnPLR55nFLHrbKbnjoioDcZyARmHt9FnZdxaZCQARgKiTHt7M0AsDcYOPng1QrbCg3NTNOOH1y4mZjgnAMlX+a2e3N7DU9Fd+5OmVexynD5skGwUn2Ds7v25MAgP+TnT59rzlRcpqFBJ2/EDRS2ZLe9qVO+akJAHPo0Wa2X2Hf0mLPbjYp+hxJ5LSH/8I5GkIJGfVkDgLAeLzBzK5a+c70Gw3JTwrrQ1bRmuCfMFQgHZCA5xdUXMf6LOiGikyJgAjAlGiOa2tpBOARZvaoca/0v9qonFHjH5ZpCzUwJOGCI573r5WK81bNxzdqhhPlTZwfORFjAiDm3VsT25MA3HN1imQjTAW1Oernt5nZ9Qfi9ucGazabrkxNAKKT95DuPrPR8ER17m1mlEkFzdMZVoQOosTa8mRqAoCJCvNF7ebf9pHMnWSMJNdATshZQF6CEwwB1Cl735VJ7xkLWJ8jX0PVhyIgAjAUsfnKL4kAkJb2W0EedOz92JPZ0Nnc+ehhN0a9ywfJk481F6pE6HFCQ/XvCWmQn9fZnLFt8tH3TBKouM/d2JO9tl7dkIT0NzQDP15d8LJH0IftSQDok3dCw66LtiJS5/fNVDC/S1KIjaD1dbidmZ3TaQSS8Jzk33EMxB+jK/QNjYonXKTDhgPpg4wQaUD56wblsaN/IPgtwocxu+vqHRjzSCAAP0zGnTl8jaDCExz1PD4a7UYdkTWaY92gafpq08a5Vjb/e2TICX4oUTgi7e3S+A+cLugrvg3vb9JL43fAe6URHW1VNGj8jn+AJ+tan31zVr9PjIAIwMSAjmhuSQTgYY3qNn0dPth8pCNHsus1dluchFLBMe0Tzr9jH+ZOAk9QU7NJ/Tv5kQtaUPd7p3nqRGTiVStic2vnQZ9piANqTuTbzebErW+csnEGxIFtrNQ4AbKJvSh4MCd4bqxjs0PVzmaH6hinSd4T+3h0OmTj5d342xPUyt6GXBIFgBr8R42TaNo2vguckCFrqUTmjiMaMoKWJ5UocQ9zBp+P1lESjQkkAmdDfCbYgKnLhtyV2jBAiDC3A3q+K2zGRFXgJNsVnPZwTPU2cUjSaTMT7uVmBknzBJPQLROnQr719wq0JbRBdkMIUSrrXJ+Z19VPcyAgAjAHqnVtLokA4MWPx38qbLhv7nm9xzde9N1ieDyzGeGxnUpkl8cRjNM8H09PONV8x/Fa52SMPRSv51Resapz20z//96cBj37eN2obltragJA62CLYyNOb6mw0XIKjNY519yinfFkDAGI7PJsyvgqfDMDZjQfICPvcurlCFJbHBMKToUlkQW1BCAKm6QPaGkwT3mSSzyESSwlKLTRmjZwNkwFjQb1fhc877lmtmfw25Ub0tT9eZ3rc4o1pjYGICACMACsmYsuiQBw0vc8tgmlelkPDrwHGxInUUID+ZsTqieU5aTozUO0EGSiy4mXqY7yqGL50KXSRwA4EUan7SmGfw4CgPMiquVIIr8HyuMA9qyg4hgCADFDM5EKJ3DU+Tnhd+zoqbx+RRxu4fx7HwFA65MjfWmTtQQAjQLOe56gYfIIGmXxj/E0Y/x2m8CEEc176rC555z60DZg7vIk9bdY9/qcYo2pjQEIiAAMAGvmoksiAJwavWuCUXFyquTvKYQPHPHPnuROp235SD2JY5ynwcgRAFTbhNXlPM7HvvPUBIDT3lkdE0m3n2yakZ8AoXmEqnlSSwDQvkD8PMGxFFNFTghjw16OmacrnGjJPZGOT44AcOLHnwV1eqnUEoDS9tNyECUIkycRQSNfgqeuR8OCWeHXPZ1BG+eFJ7Ku8WloZd3rsxZD1atEQASgErgZqi2JABD+h8rUE0KHUAviCEgSHuyanm22BCJUs5zWPSHvOhtcTlCFeirSIwNbbI4A8L7dj19J/4eWmZoA0N9onNq+5TYYTv9sMp7UEgByEXBa9wQbdET4uuUhY54tHSc2vPq7kiMAvMPQCIl1EwD8SyJCTWw/JrWukEQIMpQSJMqwFofk6+ibv+ten3390e8TIyACMDGgI5pbEgHAhojKsmR+4CiHA9HHV6p/stNBCvrCl1qYIBHXHIFZrionnPQklCMAnKh4jzllagKAoxdZ3XKCQ2Zk++bWOzzRPaklALkNdCy25JR40wACgH3dy6GQ68dUBACverRQxOlDwnA8xG+lZE21/fMIAO0RGeMJvjs3Hgtyp/661+eEXVdTJQgMmYwl7alMPQJLIgC8xeOa7GJD3wivcpy18Ejng5R68HfbwzZ6iaEPKCzPSSj1us4RACIAcKibU6YmAFFkRfoOODd6J8Y5CAChcg+aCUQ0CGkIYk4DcAMnPLGva2MJAP4v+J+QcniseAQA0xwmOk/wX8GPZSpZ9/qcqt9qpxABEYBCoNZQbC4CQNx8dIUp4Xeerb993TYTYO08YQNGxU96XU/INbDbTNjiXJXeExARAOKgvQ1y6q5NTQDwWShJgUwkxXGcl5mDANDmlJtQt9v7Ojf15QhAKUHqPmMMAWjD7GrXSzpEHgHgjopI60NuBXI5TCXrXp9T9VvtFCIw1UQtfJyKZRAgdjtyVmIh4mVcIzjTRRvwW1cbyI16GmUjJSHJZWsebmZsrniqe6F1hIMR6jeHcAELKsyuRAQApzNUtHPLViAAuTCzsfiiXWCD7kqOAKAuj7zvo77UEgBMWWTli76paMbwVyFDISaZ1pmRPA3kz/DEIwDkdyCywZOcT0cN9utenzV9VJ0RCIgAjABv4qo5Wy227NJLRdJuEX8cZUNrc+CXvApZ4VCp8qEjRJD0vaWCCprTWHq9bBRuSLsnD2L5S5/plYsIAE5V7Q1xY9rvq7sVCEDOdFSSR6IPw/T3HAEo1ZB026whAHxH0XZFZBazBZn9vHDYoU6AEFsvHwLv8JIm++FQDKPy616fU/Vb7RQiIAJQCNSainESxVHIEz4UfV7xXj1ie0md68mBZoZadaigLufjiv0e5zmy5PWp8kkVC4HoSpRkhDJnanIEDO1brrwIwLbozGECyCW2KckjMXS8l0AAco55ZOXzbqBs3xOH28iM42kAuCMgStkLMYjSKQ/FlfLrXp81fVSdEQiIAIwAb4aqqCsJf/Mkl7Ql6gpaBTLqRTeFEbJVcuVqyauyYZO2l3SunnaAUEEc7bqpZ6O73Hmel5WspB8iAP+PwDp9ACB5mJY84XIp72rjMeO6BAKA3Z0rpT2JklK1ZTHBRdk1PQKAZoy0xt63u70BcQye3brrXp9T9VvtFCIgAlAI1JqK5eLviX/Gs700xI4uR7nV+Q3bPGaFKGVo7SsT/sSpxxP8GPBnaIUwtugK377LUGr6Jw3AtqjNoQEgEQ12bk+wkXvXMdeMZVtnCQQgF/nABh8RIt7h4BVJv1MAgEcAKJqzzZPpL0rE1D4GkyDOhKnwLeCb0PonrHt9jpkHqluBgAhABWgzViHLXnTrGY9lA+NjUZJ451rNVbGRdzuhRNGtZ8wLohJQ63OnOn84vWGiKBEu06FOKhdtLj9p/52PFamAuUglFWKdya+eEwgRZggueDmq+Zv/jlIPiwBsi2YNASCNLAmYchJ5j+MLwgU3uUx1+GLgt8I4dv9EF1AtgQDkzGy7N5u8hxfJjtjMowub9mvCcdO6uQQ9fQmt+B5AEDyfIpxm8THYXuuz5NuiMhMiIAIwIZgTNMV4cDtYZAbgEYTu7WNm3BnuCelS+Qhwgt450ycc+TxbIp7EfFRJydoVnvn0gnfkghJOgKgqUyHSIT0dRglnqNuX6CZKWRxlgBMBKCcApFP2suhBPjnle7f5ta0z/9BmecLVzntl5hGbHimKU4EM4AeTasCWQAAwa+wfvFMUm09YJjZ2SH8kUabH8zbXY3v1uK6Z0F8IsSesY+9SLspyi2YarbPO9VnweVGRKREQAZgSzWnaQkXKhyEnqOiI7SfOnQ0VdT4bLg5FhOulm3faVu52Mi5OYaNMhVM1mc2iq3spz+ZPyCAfmVQOD7yko8tfqM8zIQEpHhAbvM2jhDN8VA91+iACsC0oOQ0AKXvJBe8JXu04lkb3JkBCScccnWy5E4ALbdIkUWT6I8TNu076gGCTXQIByMXmkzqbNd3V7LGBc2EPkTEIOHrfYrJrYlLzBIe/7mm9W4a7AsCye+kP7aON4LneLYKMFxkL0dJ0ZZ3rM/vR04/TIyACMD2mU7TISXvvKRpy2kC1zq1lpPD1BBUh8cpR3gGygxEexAcDhz7mEGpbzAWYFLy7zXlOzokxt9lQl9vSuNudTH2YJjiZ4nToCW1F96SLAGyLWI4AcGkPNzJGggaKuQTZRCOQnmTJ/fDCTH0c1ogM4cRKfTa6KCskl+VAbj3/lyUQANTp3HrpERcgYINH28aGzOVNRA20315+g8jmNCacwokO6l7qxPzHaRiy5Qkb+XvN7IiGiBGJEEXq0AfWVHTwWNf6nOmTp2YjBEQAljk3sInjqONdfzqmx2gN2KRRp+aE5D+coL3scTXPpy1OElFaYKIDIBa1yY7aPhFOBbmJHBtFAMoJADhyt0OJoIXCvJMKp3kS14wRbP/0JcpmuQQCwPtxst6j4kXZ+DEhYFLpW2/p95qIizdMkMUSkwymmUjWtT4r4FOVMQiIAIxBb966jA2nZjyM+z4MfT1h48Xuh301VfFFdclOBvNn8Y8R7gPArNAN//Paw4RB2Ujl2deHjzVqz8j2SX0RgG1RzGkAKFmaCz4iABBZtFlRHoq+MUXLhCo7TSDVrbcUAkAmSVTvffkwun3vOvUSDYO5Kyfe95orsQnlrUlkRXgo/hrp/Qrba332zQf9PjECIgATAzpDc9jlMAeQRCVKEhQ9lk2XTRzHvshpMNdl1JXYarFx5hwKvTaw+WPrja6G9eqgQt2zuYRo10IsiYkmoRF50PuiI0QAhhEAnO5wtGQO5iQiAG0d1MuYFFDjlwgklSyVzJ++u+2XQgB4L7QgbOS5xD+Uw7eFUz9Ofq0fBREB3EZ5ygxA0feaqAycEPlGePZ9r0nU/Rww0uuVc+Mz9/osmRsqMyECIgATgjlzU2z+sH2y7mErxRYO6+fkwUcEVSl/sEVyEsFBkHj8KeL8SSREWCGnc044bAxoBribnE0X2zwfakKaUNVi2yWaoVZIJMTzuKiIzGfYiHdpSAihiIQOou7HEYo/pbkRRACGEQBKM+9QEXPNLKluGRvm1NGNTRvbNv4Z2JtzwreGeykwQfE3viLYzplD+KPgCwBJxVzElb99Zqr2WUsiAG2fcM7D9EGkDaQAPwnwIl0woXYHBV76kICHNxix5lhbrGd8LZjnh/RgDBHA4ZB1w22E4ItmDSdhNGOQcjRlmA0Oq12czRyYY32O6JKq1iAgAlCDmuoIASEgBISAENhwBEQANnwA1X0hIASEgBAQAjUIiADUoKY6QkAICAEhIAQ2HAERgA0fQHVfCAgBISAEhEANAiIANaipjhAQAkJACAiBDUdABGDDB1DdFwJCQAgIASFQg4AIQA1qqiMEhIAQEAJCYMMREAHY8AFU94WAEBACQkAI1CAgAlCDmuoIASEgBISAENhwBEQANnwA1X0hIASEgBAQAjUIiADUoKY6QkAICAEhIAQ2HAERgA0fQHVfCAgBISAEhEANAiIANaipjhAQAkJACAiBDUdABGDDB1DdFwJCQAgIASFQg4AIQA1qqiMEhIAQEAJCYMMREAHY8AFU94WAEBACQkAI1CAgAlCDmuoIASEgBISAENhwBEQANnwA1X0hIASEgBAQAjUIiADUoKY6QkAICAEhIAQ2HAERgA0fQHVfCAgBISAEhEANAiIANaipjhAQAkJACAiBDUdABGDDB1DdFwJCQAgIASFQg4AIQA1qqiMEhIAQEAJCYMMREAHY8AFU94WAEBACQkAI1CDwX14LxYGZtibWAAAAAElFTkSuQmCC"/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-141"><g><path d="M 293.63 41 L 265 41 L 265 100.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 298.88 41 L 291.88 44.5 L 293.63 41 L 291.88 37.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 265 105.88 L 261.5 98.88 L 265 100.63 L 268.5 98.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-142"><g><ellipse cx="315" cy="7.5" rx="7.5" ry="7.5" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><path d="M 315 15 L 315 40 M 315 20 L 300 20 M 315 20 L 330 20 M 315 40 L 300 60 M 315 40 L 330 60" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 67px; margin-left: 315px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;">Machine</div></div></div></foreignObject><image x="292.5" y="67.5" width="45" height="17" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-143"><g><path d="M 75 428.63 L 75 411 L 186 411 L 186 376 C 189.9 376 189.9 370 186 370 L 186 370 L 186 341 L 232.5 341 L 232.5 153.37" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 75 433.88 L 71.5 426.88 L 75 428.63 L 78.5 426.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 232.5 148.12 L 236 155.12 L 232.5 153.37 L 229 155.12 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-144"><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 221px; margin-left: 232px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">HTTP</div></div></div></foreignObject><image x="217.5" y="215" width="29" height="15.75" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHQAAAA/CAYAAAAxBeyIAAAAAXNSR0IArs4c6QAAA/xJREFUeF7tm78vNEEYx78rEoUG0VGJHxGJSIiIQuFHkKAglCRErVKQUChIUPgDRChPUIqCwu9EQSHRiEgkNKIhUQg5mXvf2/f23tubW7Nr5jbf7dzMPM8z388882uXFY1Go+ATGgUsAg0Ny1hHCDRcPAk0ZDwJlEDDpkDI+sM1lEBDpkDIusMMDTPQ1dVVjI+P213s7OzE3t6eUpeLi4vx8vJi27i6ukJdXZ399/7+Pjo6OpR8yBqPjIxgfX0dv+krMabS0lI8Pj7KwnSU5+fno6CgAKJtY2MjWltb0dPTg9zc3LR2HBlKoJ40T1k5PnhUgaYyLuDOzs46ki65HoGqM3RYCBJo3FFfXx82NzeRl5f3X/TagT49PWF3dzcjWaenp/H8/GzXnZqaQllZmbRtZWUlWlpa8Ju+0mXo/Pw8KioqXOP++vrC6+sr7u/vcXZ2hqOjIyRfuQ8MDGBra8s8oFIaCRXKy8txd3dn/3J+fo6mpiYvJjKu66ev5DXUa9y3t7exafbw8NARfyQSwdDQkOM37RmascIA/BRZ5tdPX6pARawfHx9ob2/H8fGxHXp1dTVubm4IVAZTlJsGVMR0fX2N2tpaR/gie0Ws8YcZ6kLXRKAi1JqaGkdWbmxsYHh4mEBlWWoq0MHBQcdmaHFxEZOTkwSarUDHxsawtrZmhz8zM4O5uTkCzVag4riys7Njh7+ysoKJiQkCzVagyUvB9vY2+vv7CTQbgV5eXqK+vt4OPScnJ3bRUlRUlBlQcZuRuIOSiZCqfGFhAe/v73ZR8uW8F5t+blRkfv305dc5tK2tDScnJ3boqV6epD22yDr9k3ICBbzeFD08PGB0dBQHBwf/MtGycHFxgYaGhswvFn4CTNaGQIHl5WVUVVW5SiXubd/e3iBAnp6exl5hfn5+OuqLna3Y4SY/zFANFwuyQS8rF+dOcf5M9fCmKIuAiqxeWlpCb2+vK3MCNRSoeNdZWFiIkpISNDc3o6urC93d3bAsK20CE6gGoF43RbIpOLGcQAnUy3gBZB+JebHm59lQ5tdPX36cQ2XxxsuZoczQTMfKn3rMUMQ+xUz8jJNr6N8x5Oc0KBuWfvoi0F+YBglUpoBLOadcTrmuQ8fPaVA2Pv30xSmXU65svPHqz6tCzFCuoa5jRtuU63UUs755CvAffs1johQRgSrJZ15jAjWPiVJEBKokn3mNCdQ8JkoREaiSfOY1JlDzmChFRKBK8pnXmEDNY6IUEYEqyWdeYwI1j4lSROm/2lUyzcY6FCBQHaoH6JNAAxRXh2kC1aF6gD4JNEBxdZgmUB2qB+iTQAMUV4dpAtWheoA+CTRAcXWYJlAdqgfok0ADFFeH6W97Qt2suZ3FFgAAAABJRU5ErkJggg=="/></switch></g></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-145"><g><path d="M 530 497.35 L 530 478.47" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-146"><g><path d="M 220 502.88 L 220 488" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-147"><g><path d="M 336.37 127 L 363 127 L 363 291 L 383.63 291" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 331.12 127 L 338.12 123.5 L 336.37 127 L 338.12 130.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 388.88 291 L 381.88 294.5 L 383.63 291 L 381.88 287.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-148"><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 217px; margin-left: 364px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">HTTP</div></div></div></foreignObject><image x="349.5" y="211" width="29" height="15.75" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHQAAAA/CAYAAAAxBeyIAAAAAXNSR0IArs4c6QAAA/xJREFUeF7tm78vNEEYx78rEoUG0VGJHxGJSIiIQuFHkKAglCRErVKQUChIUPgDRChPUIqCwu9EQSHRiEgkNKIhUQg5mXvf2/f23tubW7Nr5jbf7dzMPM8z388882uXFY1Go+ATGgUsAg0Ny1hHCDRcPAk0ZDwJlEDDpkDI+sM1lEBDpkDIusMMDTPQ1dVVjI+P213s7OzE3t6eUpeLi4vx8vJi27i6ukJdXZ399/7+Pjo6OpR8yBqPjIxgfX0dv+krMabS0lI8Pj7KwnSU5+fno6CgAKJtY2MjWltb0dPTg9zc3LR2HBlKoJ40T1k5PnhUgaYyLuDOzs46ki65HoGqM3RYCBJo3FFfXx82NzeRl5f3X/TagT49PWF3dzcjWaenp/H8/GzXnZqaQllZmbRtZWUlWlpa8Ju+0mXo/Pw8KioqXOP++vrC6+sr7u/vcXZ2hqOjIyRfuQ8MDGBra8s8oFIaCRXKy8txd3dn/3J+fo6mpiYvJjKu66ev5DXUa9y3t7exafbw8NARfyQSwdDQkOM37RmascIA/BRZ5tdPX6pARawfHx9ob2/H8fGxHXp1dTVubm4IVAZTlJsGVMR0fX2N2tpaR/gie0Ws8YcZ6kLXRKAi1JqaGkdWbmxsYHh4mEBlWWoq0MHBQcdmaHFxEZOTkwSarUDHxsawtrZmhz8zM4O5uTkCzVag4riys7Njh7+ysoKJiQkCzVagyUvB9vY2+vv7CTQbgV5eXqK+vt4OPScnJ3bRUlRUlBlQcZuRuIOSiZCqfGFhAe/v73ZR8uW8F5t+blRkfv305dc5tK2tDScnJ3boqV6epD22yDr9k3ICBbzeFD08PGB0dBQHBwf/MtGycHFxgYaGhswvFn4CTNaGQIHl5WVUVVW5SiXubd/e3iBAnp6exl5hfn5+OuqLna3Y4SY/zFANFwuyQS8rF+dOcf5M9fCmKIuAiqxeWlpCb2+vK3MCNRSoeNdZWFiIkpISNDc3o6urC93d3bAsK20CE6gGoF43RbIpOLGcQAnUy3gBZB+JebHm59lQ5tdPX36cQ2XxxsuZoczQTMfKn3rMUMQ+xUz8jJNr6N8x5Oc0KBuWfvoi0F+YBglUpoBLOadcTrmuQ8fPaVA2Pv30xSmXU65svPHqz6tCzFCuoa5jRtuU63UUs755CvAffs1johQRgSrJZ15jAjWPiVJEBKokn3mNCdQ8JkoREaiSfOY1JlDzmChFRKBK8pnXmEDNY6IUEYEqyWdeYwI1j4lSROm/2lUyzcY6FCBQHaoH6JNAAxRXh2kC1aF6gD4JNEBxdZgmUB2qB+iTQAMUV4dpAtWheoA+CTRAcXWYJlAdqgfok0ADFFeH6W97Qt2suZ3FFgAAAABJRU5ErkJggg=="/></switch></g></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-149"><g><path d="M 383.63 137 L 377 137 L 377 288 C 380.9 288 380.9 294 377 294 L 377 294 L 377 328 C 380.9 328 380.9 334 377 334 L 377 334 L 377 370 C 380.9 370 380.9 376 377 376 L 377 376 L 377 408 C 380.9 408 380.9 414 377 414 L 377 414 L 377 418 C 380.9 418 380.9 424 377 424 L 377 424 L 377 445 L 390 445" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 388.88 137 L 381.88 140.5 L 383.63 137 L 381.88 133.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-150"><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 238px; margin-left: 381px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">HTTP</div></div></div></foreignObject><image x="366.5" y="232" width="29" height="15.75" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHQAAAA/CAYAAAAxBeyIAAAAAXNSR0IArs4c6QAAA/xJREFUeF7tm78vNEEYx78rEoUG0VGJHxGJSIiIQuFHkKAglCRErVKQUChIUPgDRChPUIqCwu9EQSHRiEgkNKIhUQg5mXvf2/f23tubW7Nr5jbf7dzMPM8z388882uXFY1Go+ATGgUsAg0Ny1hHCDRcPAk0ZDwJlEDDpkDI+sM1lEBDpkDIusMMDTPQ1dVVjI+P213s7OzE3t6eUpeLi4vx8vJi27i6ukJdXZ399/7+Pjo6OpR8yBqPjIxgfX0dv+krMabS0lI8Pj7KwnSU5+fno6CgAKJtY2MjWltb0dPTg9zc3LR2HBlKoJ40T1k5PnhUgaYyLuDOzs46ki65HoGqM3RYCBJo3FFfXx82NzeRl5f3X/TagT49PWF3dzcjWaenp/H8/GzXnZqaQllZmbRtZWUlWlpa8Ju+0mXo/Pw8KioqXOP++vrC6+sr7u/vcXZ2hqOjIyRfuQ8MDGBra8s8oFIaCRXKy8txd3dn/3J+fo6mpiYvJjKu66ev5DXUa9y3t7exafbw8NARfyQSwdDQkOM37RmascIA/BRZ5tdPX6pARawfHx9ob2/H8fGxHXp1dTVubm4IVAZTlJsGVMR0fX2N2tpaR/gie0Ws8YcZ6kLXRKAi1JqaGkdWbmxsYHh4mEBlWWoq0MHBQcdmaHFxEZOTkwSarUDHxsawtrZmhz8zM4O5uTkCzVag4riys7Njh7+ysoKJiQkCzVagyUvB9vY2+vv7CTQbgV5eXqK+vt4OPScnJ3bRUlRUlBlQcZuRuIOSiZCqfGFhAe/v73ZR8uW8F5t+blRkfv305dc5tK2tDScnJ3boqV6epD22yDr9k3ICBbzeFD08PGB0dBQHBwf/MtGycHFxgYaGhswvFn4CTNaGQIHl5WVUVVW5SiXubd/e3iBAnp6exl5hfn5+OuqLna3Y4SY/zFANFwuyQS8rF+dOcf5M9fCmKIuAiqxeWlpCb2+vK3MCNRSoeNdZWFiIkpISNDc3o6urC93d3bAsK20CE6gGoF43RbIpOLGcQAnUy3gBZB+JebHm59lQ5tdPX36cQ2XxxsuZoczQTMfKn3rMUMQ+xUz8jJNr6N8x5Oc0KBuWfvoi0F+YBglUpoBLOadcTrmuQ8fPaVA2Pv30xSmXU65svPHqz6tCzFCuoa5jRtuU63UUs755CvAffs1johQRgSrJZ15jAjWPiVJEBKokn3mNCdQ8JkoREaiSfOY1JlDzmChFRKBK8pnXmEDNY6IUEYEqyWdeYwI1j4lSROm/2lUyzcY6FCBQHaoH6JNAAxRXh2kC1aF6gD4JNEBxdZgmUB2qB+iTQAMUV4dpAtWheoA+CTRAcXWYJlAdqgfok0ADFFeH6W97Qt2suZ3FFgAAAABJRU5ErkJggg=="/></switch></g></g></g></g></g></g></g></svg> \ No newline at end of file diff --git a/.docs/images/architecture.drawio b/.docs/images/architecture.drawio index 8433da025fa2c2ecf2221a4794a2e2f693df6042..8e44f6c84bbcc9c0d0e1197f512d6748fb128d68 100644 --- a/.docs/images/architecture.drawio +++ b/.docs/images/architecture.drawio @@ -1,303 +1,362 @@ -<mxfile host="Electron" modified="2024-07-18T03:24:43.687Z" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/24.6.4 Chrome/124.0.6367.207 Electron/30.0.6 Safari/537.36" etag="yfnnaSFCfO3oi8Cn43Ov" version="24.6.4" type="device" pages="8"> +<mxfile host="Electron" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/24.7.17 Chrome/128.0.6613.36 Electron/32.0.1 Safari/537.36" version="24.7.17" pages="8"> <diagram id="mvBsv1rP8O80Qe3yGnn_" name="docker-compose"> <mxGraphModel dx="683" dy="391" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1169" pageHeight="827" math="0" shadow="0"> <root> <mxCell id="0" /> <mxCell id="1" parent="0" /> - <mxCell id="45LT9Xtm5jvL1Omwo4Uv-6" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;strokeColor=#000000;startArrow=classic;startFill=1;dashed=1;" parent="1" target="CohMdi7D_fRk0dSxzjYi-1" edge="1"> - <mxGeometry x="-0.028" relative="1" as="geometry"> - <mxPoint x="448" y="230" as="sourcePoint" /> - <mxPoint as="offset" /> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-76" value="" style="rounded=1;whiteSpace=wrap;html=1;fillColor=none;dashed=1;arcSize=2;" parent="1" vertex="1"> + <mxGeometry x="320" y="160" width="640" height="397" as="geometry" /> + </mxCell> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-77" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.75;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;startArrow=classic;startFill=1;endArrow=classic;endFill=1;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-119" target="FWEJ_FGA9GBXbfwohBE8-108" edge="1"> + <mxGeometry relative="1" as="geometry"> + <Array as="points"> + <mxPoint x="668" y="206" /> + <mxPoint x="668" y="400" /> + <mxPoint x="775" y="400" /> + </Array> </mxGeometry> </mxCell> - <mxCell id="S3Av5TdVFqS_SrXukbwN-2" value="Researcher" style="shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;outlineConnect=0;" parent="1" vertex="1"> - <mxGeometry x="433.5" y="146" width="30" height="60" as="geometry" /> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-78" value="HTTP" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="FWEJ_FGA9GBXbfwohBE8-77" vertex="1" connectable="0"> + <mxGeometry x="-0.2051" y="1" relative="1" as="geometry"> + <mxPoint x="61" y="40" as="offset" /> + </mxGeometry> + </mxCell> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-79" value="HTTP" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="FWEJ_FGA9GBXbfwohBE8-77" vertex="1" connectable="0"> + <mxGeometry x="-0.3724" relative="1" as="geometry"> + <mxPoint x="-2" y="11" as="offset" /> + </mxGeometry> </mxCell> - <mxCell id="V1Wl26Vbpgnno5Lb-wtg-39" value="HTTP" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;startArrow=classic;startFill=1;fontSize=9;" parent="1" source="CohMdi7D_fRk0dSxzjYi-1" target="S3Av5TdVFqS_SrXukbwN-1" edge="1"> - <mxGeometry x="0.0013" relative="1" as="geometry"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-80" value="" style="rounded=1;whiteSpace=wrap;html=1;fillColor=none;dashed=1;arcSize=6;" parent="1" vertex="1"> + <mxGeometry x="540" y="557" width="420" height="123" as="geometry" /> + </mxCell> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-81" value="LDAP" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;startArrow=classic;startFill=1;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-96" target="FWEJ_FGA9GBXbfwohBE8-104" edge="1"> + <mxGeometry x="-0.2381" relative="1" as="geometry"> <mxPoint as="offset" /> </mxGeometry> </mxCell> - <mxCell id="V1Wl26Vbpgnno5Lb-wtg-40" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.25;exitY=1;exitDx=0;exitDy=0;" parent="1" source="CohMdi7D_fRk0dSxzjYi-1" target="AQz-Vj6r_5Wor37pQVs6-1" edge="1"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-82" value="data-db" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;spacing=-1;" parent="1" vertex="1"> + <mxGeometry x="352.5" y="658" width="85" height="20" as="geometry" /> + </mxCell> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-83" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.25;exitY=0;exitDx=0;exitDy=0;startArrow=classic;startFill=1;endArrow=none;endFill=0;entryX=0.25;entryY=1;entryDx=0;entryDy=0;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-85" target="FWEJ_FGA9GBXbfwohBE8-92" edge="1"> <mxGeometry relative="1" as="geometry" /> </mxCell> - <mxCell id="V1Wl26Vbpgnno5Lb-wtg-41" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.75;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="CohMdi7D_fRk0dSxzjYi-1" target="SsHHCok0RUWS7ODwTELy-4" edge="1"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-84" value="AMQP" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="FWEJ_FGA9GBXbfwohBE8-83" vertex="1" connectable="0"> + <mxGeometry x="-0.0476" y="-1" relative="1" as="geometry"> + <mxPoint x="-1" y="-4" as="offset" /> + </mxGeometry> + </mxCell> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-85" value="Data Service" style="rounded=1;whiteSpace=wrap;html=1;fontStyle=1" parent="1" vertex="1"> + <mxGeometry x="330" y="504" width="130" height="40" as="geometry" /> + </mxCell> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-86" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;entryPerimeter=0;startArrow=classic;startFill=1;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-85" target="FWEJ_FGA9GBXbfwohBE8-137" edge="1"> <mxGeometry relative="1" as="geometry" /> </mxCell> - <mxCell id="V1Wl26Vbpgnno5Lb-wtg-42" value="HTTP" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;startArrow=classic;startFill=1;fontSize=9;" parent="1" source="CohMdi7D_fRk0dSxzjYi-1" target="13tBXMPt0xomx7MP2VuM-1" edge="1"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-87" value="JDBC" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="FWEJ_FGA9GBXbfwohBE8-86" vertex="1" connectable="0"> + <mxGeometry x="0.3566" relative="1" as="geometry"> + <mxPoint y="-11" as="offset" /> + </mxGeometry> + </mxCell> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-88" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;startArrow=classic;startFill=1;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-92" target="FWEJ_FGA9GBXbfwohBE8-96" edge="1"> <mxGeometry relative="1" as="geometry" /> </mxCell> - <mxCell id="V1Wl26Vbpgnno5Lb-wtg-43" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.25;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;startArrow=classic;startFill=1;" parent="1" source="CohMdi7D_fRk0dSxzjYi-1" target="O_ELZSFbvl3Butg3bv_j-1" edge="1"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-89" value="LDAP" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="FWEJ_FGA9GBXbfwohBE8-88" vertex="1" connectable="0"> + <mxGeometry x="-0.1051" y="-1" relative="1" as="geometry"> + <mxPoint x="3" y="-1" as="offset" /> + </mxGeometry> + </mxCell> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-90" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0;entryY=0.75;entryDx=0;entryDy=0;startArrow=classic;startFill=1;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-92" target="FWEJ_FGA9GBXbfwohBE8-119" edge="1"> <mxGeometry relative="1" as="geometry"> <Array as="points"> - <mxPoint x="415" y="346" /> - <mxPoint x="362" y="346" /> - <mxPoint x="362" y="440" /> - <mxPoint x="275" y="440" /> + <mxPoint x="395" y="400" /> + <mxPoint x="500" y="400" /> + <mxPoint x="500" y="206" /> </Array> </mxGeometry> </mxCell> - <mxCell id="YJRAzF6yD4Hh-bAvO1PB-19" value="HTTP" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];fontSize=9;" parent="V1Wl26Vbpgnno5Lb-wtg-43" vertex="1" connectable="0"> - <mxGeometry x="-0.6602" relative="1" as="geometry"> - <mxPoint x="-3" as="offset" /> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-91" value="HTTP,<div>AMQP</div>" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="FWEJ_FGA9GBXbfwohBE8-90" vertex="1" connectable="0"> + <mxGeometry x="-0.1797" y="2" relative="1" as="geometry"> + <mxPoint x="2" y="-77" as="offset" /> </mxGeometry> </mxCell> - <mxCell id="V1Wl26Vbpgnno5Lb-wtg-44" value="S3" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;startArrow=classic;startFill=1;fontSize=9;" parent="1" source="CohMdi7D_fRk0dSxzjYi-1" target="V1Wl26Vbpgnno5Lb-wtg-38" edge="1"> - <mxGeometry x="0.0034" relative="1" as="geometry"> - <mxPoint as="offset" /> - </mxGeometry> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-92" value="<b>Broker Service</b><div><i>rabbitmq</i></div>" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#E6E6E6;fontColor=#000000;strokeColor=#000000;" parent="1" vertex="1"> + <mxGeometry x="330" y="422" width="130" height="40" as="geometry" /> </mxCell> - <mxCell id="V1Wl26Vbpgnno5Lb-wtg-45" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.75;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;startArrow=classic;startFill=1;" parent="1" source="CohMdi7D_fRk0dSxzjYi-1" target="hBEam5F8n4ZBPeoiEcWH-1" edge="1"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-93" value="LDAP" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;startArrow=classic;startFill=1;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-96" target="FWEJ_FGA9GBXbfwohBE8-108" edge="1"> <mxGeometry relative="1" as="geometry"> - <Array as="points"> - <mxPoint x="480" y="346" /> - <mxPoint x="538" y="346" /> - <mxPoint x="538" y="430" /> - <mxPoint x="625" y="430" /> - </Array> + <mxPoint as="offset" /> </mxGeometry> </mxCell> - <mxCell id="YJRAzF6yD4Hh-bAvO1PB-18" value="HTTP" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];fontSize=9;" parent="V1Wl26Vbpgnno5Lb-wtg-45" vertex="1" connectable="0"> - <mxGeometry x="-0.7352" y="1" relative="1" as="geometry"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-94" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;startArrow=classic;startFill=1;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-96" target="FWEJ_FGA9GBXbfwohBE8-119" edge="1"> + <mxGeometry relative="1" as="geometry" /> + </mxCell> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-95" value="HTTP" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="FWEJ_FGA9GBXbfwohBE8-94" vertex="1" connectable="0"> + <mxGeometry x="0.125" relative="1" as="geometry"> <mxPoint as="offset" /> </mxGeometry> </mxCell> - <mxCell id="CohMdi7D_fRk0dSxzjYi-1" value="Gateway Service<br>(NGINX)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#E6E6E6;fontColor=#000000;strokeColor=#000000;" parent="1" vertex="1"> - <mxGeometry x="382.5" y="278" width="130" height="40" as="geometry" /> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-96" value="<b>Identity Service *</b><div><i>openldap</i></div>" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#E6E6E6;fontColor=#000000;strokeColor=#000000;" parent="1" vertex="1"> + <mxGeometry x="520" y="422" width="130" height="40" as="geometry" /> </mxCell> - <mxCell id="iy0HhJzZLXsiPmpU2ukH-9" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;jumpStyle=arc;" parent="1" source="13tBXMPt0xomx7MP2VuM-1" target="V1Wl26Vbpgnno5Lb-wtg-38" edge="1"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-97" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.75;entryY=1;entryDx=0;entryDy=0;jumpStyle=arc;startArrow=classic;startFill=1;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-101" target="FWEJ_FGA9GBXbfwohBE8-119" edge="1"> <mxGeometry relative="1" as="geometry"> <Array as="points"> - <mxPoint x="526" y="394" /> - <mxPoint x="526" y="335" /> - <mxPoint x="625" y="335" /> + <mxPoint x="775" y="480" /> + <mxPoint x="662" y="480" /> + <mxPoint x="662" y="410" /> + <mxPoint x="617" y="410" /> </Array> </mxGeometry> </mxCell> - <mxCell id="iy0HhJzZLXsiPmpU2ukH-10" value="S3" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="iy0HhJzZLXsiPmpU2ukH-9" vertex="1" connectable="0"> - <mxGeometry x="0.0562" y="3" relative="1" as="geometry"> - <mxPoint y="3" as="offset" /> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-98" value="HTTP" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="FWEJ_FGA9GBXbfwohBE8-97" vertex="1" connectable="0"> + <mxGeometry x="0.7012" y="1" relative="1" as="geometry"> + <mxPoint x="1" y="2" as="offset" /> </mxGeometry> </mxCell> - <mxCell id="f61RwCrreTIYbJ5Vt7fi-16" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.75;exitY=1;exitDx=0;exitDy=0;entryX=0.25;entryY=0;entryDx=0;entryDy=0;startArrow=classic;startFill=1;endArrow=none;endFill=0;" edge="1" parent="1" source="13tBXMPt0xomx7MP2VuM-1" target="hBEam5F8n4ZBPeoiEcWH-1"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-99" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.25;exitY=0;exitDx=0;exitDy=0;entryX=0.75;entryY=0;entryDx=0;entryDy=0;jumpStyle=arc;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-101" target="FWEJ_FGA9GBXbfwohBE8-85" edge="1"> <mxGeometry relative="1" as="geometry"> <Array as="points"> - <mxPoint x="480" y="450" /> - <mxPoint x="593" y="450" /> + <mxPoint x="743" y="490" /> + <mxPoint x="427" y="490" /> </Array> </mxGeometry> </mxCell> - <mxCell id="13tBXMPt0xomx7MP2VuM-1" value="Analyse Service" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1"> - <mxGeometry x="382.5" y="374" width="130" height="40" as="geometry" /> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-100" value="HTTP" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="FWEJ_FGA9GBXbfwohBE8-99" vertex="1" connectable="0"> + <mxGeometry x="0.3494" relative="1" as="geometry"> + <mxPoint as="offset" /> + </mxGeometry> + </mxCell> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-101" value="Metadata Service" style="rounded=1;whiteSpace=wrap;html=1;fontStyle=1" parent="1" vertex="1"> + <mxGeometry x="710" y="504" width="130" height="40" as="geometry" /> </mxCell> - <mxCell id="V1Wl26Vbpgnno5Lb-wtg-46" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;entryPerimeter=0;startArrow=classic;startFill=1;" parent="1" source="O_ELZSFbvl3Butg3bv_j-1" target="V1Wl26Vbpgnno5Lb-wtg-36" edge="1"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-102" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.75;exitDx=0;exitDy=0;entryX=0;entryY=0.75;entryDx=0;entryDy=0;startArrow=classic;startFill=1;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-104" target="FWEJ_FGA9GBXbfwohBE8-101" edge="1"> <mxGeometry relative="1" as="geometry" /> </mxCell> - <mxCell id="O_ELZSFbvl3Butg3bv_j-1" value="Authentication Service<br>(Keycloak)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#E6E6E6;fontColor=#000000;strokeColor=#000000;" parent="1" vertex="1"> - <mxGeometry x="210" y="470" width="130" height="40" as="geometry" /> - </mxCell> - <mxCell id="V1Wl26Vbpgnno5Lb-wtg-48" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;entryPerimeter=0;startArrow=classic;startFill=1;" parent="1" target="V1Wl26Vbpgnno5Lb-wtg-32" edge="1"> - <mxGeometry relative="1" as="geometry"> - <mxPoint x="689.9999999999998" y="490" as="sourcePoint" /> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-103" value="HTTP" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="FWEJ_FGA9GBXbfwohBE8-102" vertex="1" connectable="0"> + <mxGeometry x="-0.1111" relative="1" as="geometry"> + <mxPoint x="3" as="offset" /> </mxGeometry> </mxCell> - <mxCell id="YJRAzF6yD4Hh-bAvO1PB-16" value="JDBC" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];fontSize=9;" parent="V1Wl26Vbpgnno5Lb-wtg-48" vertex="1" connectable="0"> - <mxGeometry x="-0.2851" y="-2" relative="1" as="geometry"> - <mxPoint x="6" y="-2" as="offset" /> - </mxGeometry> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-104" value="<b>Auth Service</b><br><i>keycloak</i>" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#E6E6E6;fontColor=#000000;strokeColor=#000000;" parent="1" vertex="1"> + <mxGeometry x="520" y="504" width="130" height="40" as="geometry" /> </mxCell> - <mxCell id="iy0HhJzZLXsiPmpU2ukH-6" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="hBEam5F8n4ZBPeoiEcWH-1" target="iy0HhJzZLXsiPmpU2ukH-4" edge="1"> - <mxGeometry relative="1" as="geometry" /> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-105" value="Search Service" style="rounded=1;whiteSpace=wrap;html=1;fontStyle=1" parent="1" vertex="1"> + <mxGeometry x="710" y="176" width="130" height="40" as="geometry" /> </mxCell> - <mxCell id="f61RwCrreTIYbJ5Vt7fi-15" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.75;exitY=0;exitDx=0;exitDy=0;entryX=0.75;entryY=1;entryDx=0;entryDy=0;" edge="1" parent="1" source="hBEam5F8n4ZBPeoiEcWH-1" target="SsHHCok0RUWS7ODwTELy-4"> - <mxGeometry relative="1" as="geometry" /> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-106" value="" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=8.600000000000023;fillColor=#E6E6E6;strokeColor=#000000;" parent="1" vertex="1"> + <mxGeometry x="750" y="256" width="50" height="64" as="geometry" /> </mxCell> - <mxCell id="hBEam5F8n4ZBPeoiEcWH-1" value="Metadata Service" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1"> - <mxGeometry x="560" y="470" width="130" height="40" as="geometry" /> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-107" value="search-db" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;spacing=-1;" parent="1" vertex="1"> + <mxGeometry x="732.5" y="320.5" width="85" height="17" as="geometry" /> </mxCell> - <mxCell id="YJRAzF6yD4Hh-bAvO1PB-15" value="Spring AMQP" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;jumpStyle=arc;dashed=1;strokeWidth=1;dashPattern=1 1;fontSize=9;" parent="1" source="AQz-Vj6r_5Wor37pQVs6-1" target="YJRAzF6yD4Hh-bAvO1PB-1" edge="1"> - <mxGeometry x="0.54" relative="1" as="geometry"> - <Array as="points"> - <mxPoint x="370" y="394" /> - <mxPoint x="370" y="440" /> - <mxPoint x="450" y="440" /> - </Array> - <mxPoint as="offset" /> - </mxGeometry> - </mxCell> - <mxCell id="AQz-Vj6r_5Wor37pQVs6-1" value="Broker Service<br>(RabbitMQ)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#E6E6E6;fontColor=#000000;strokeColor=#000000;" parent="1" vertex="1"> - <mxGeometry x="208" y="374" width="130" height="40" as="geometry" /> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-108" value="<b>Dashboard Service</b><div><i>grafana</i></div>" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#E6E6E6;fontColor=#000000;strokeColor=#000000;" parent="1" vertex="1"> + <mxGeometry x="710" y="422" width="130" height="40" as="geometry" /> </mxCell> - <mxCell id="V1Wl26Vbpgnno5Lb-wtg-49" value="HTTP" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;entryPerimeter=0;startArrow=classic;startFill=1;fontSize=9;" parent="1" source="SsHHCok0RUWS7ODwTELy-4" target="V1Wl26Vbpgnno5Lb-wtg-26" edge="1"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-109" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-124" target="FWEJ_FGA9GBXbfwohBE8-120" edge="1"> <mxGeometry relative="1" as="geometry" /> </mxCell> - <mxCell id="SsHHCok0RUWS7ODwTELy-4" value="Search Service" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1"> - <mxGeometry x="560" y="374" width="130" height="40" as="geometry" /> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-110" value="S3" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="FWEJ_FGA9GBXbfwohBE8-109" vertex="1" connectable="0"> + <mxGeometry x="0.2961" y="-3" relative="1" as="geometry"> + <mxPoint x="3" y="-9" as="offset" /> + </mxGeometry> + </mxCell> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-111" value="" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=8.600000000000023;fillColor=#E6E6E6;strokeColor=#000000;" parent="1" vertex="1"> + <mxGeometry x="560" y="584" width="50" height="64" as="geometry" /> + </mxCell> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-112" value="auth-db" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;spacing=-1;" parent="1" vertex="1"> + <mxGeometry x="542.5" y="648" width="85" height="20" as="geometry" /> </mxCell> - <mxCell id="S3Av5TdVFqS_SrXukbwN-1" value="UI" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1"> - <mxGeometry x="210" y="278" width="130" height="40" as="geometry" /> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-113" value="" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=8.600000000000023;fillColor=#E6E6E6;strokeColor=#000000;" parent="1" vertex="1"> + <mxGeometry x="750" y="584" width="50" height="64" as="geometry" /> </mxCell> - <mxCell id="V1Wl26Vbpgnno5Lb-wtg-26" value="" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=8.600000000000023;fillColor=#E6E6E6;strokeColor=#000000;" parent="1" vertex="1"> - <mxGeometry x="740" y="362" width="50" height="64" as="geometry" /> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-114" value="metadata-db" style="text;html=1;strokeColor=none;fillColor=default;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;spacing=-1;" parent="1" vertex="1"> + <mxGeometry x="732.5" y="649" width="85" height="17" as="geometry" /> </mxCell> - <mxCell id="A18w2Y2_AVEIFkgUy5Lv-4" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;startArrow=classic;startFill=1;endArrow=none;endFill=0;" parent="1" source="V1Wl26Vbpgnno5Lb-wtg-32" edge="1"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-115" value="HTTP" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.25;exitDx=0;exitDy=0;entryX=0;entryY=0.25;entryDx=0;entryDy=0;startArrow=classic;startFill=1;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-119" target="FWEJ_FGA9GBXbfwohBE8-105" edge="1"> <mxGeometry relative="1" as="geometry"> - <mxPoint x="850" y="490" as="targetPoint" /> + <mxPoint as="offset" /> </mxGeometry> </mxCell> - <mxCell id="V1Wl26Vbpgnno5Lb-wtg-32" value="" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=8.600000000000023;fillColor=#E6E6E6;strokeColor=#000000;" parent="1" vertex="1"> - <mxGeometry x="740" y="458" width="50" height="64" as="geometry" /> - </mxCell> - <mxCell id="V1Wl26Vbpgnno5Lb-wtg-33" value="metadata-db" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;spacing=-1;" parent="1" vertex="1"> - <mxGeometry x="722.5" y="522" width="85" height="20" as="geometry" /> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-116" value="HTTP" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.25;exitDx=0;exitDy=0;entryX=1;entryY=0.25;entryDx=0;entryDy=0;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-119" target="FWEJ_FGA9GBXbfwohBE8-124" edge="1"> + <mxGeometry relative="1" as="geometry"> + <Array as="points"> + <mxPoint x="490" y="186" /> + <mxPoint x="490" y="186" /> + </Array> + <mxPoint as="offset" /> + </mxGeometry> </mxCell> - <mxCell id="V1Wl26Vbpgnno5Lb-wtg-34" value="" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=8.600000000000023;fillColor=#E6E6E6;strokeColor=#000000;" parent="1" vertex="1"> - <mxGeometry x="423.5" y="551" width="50" height="64" as="geometry" /> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-117" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;startArrow=classic;startFill=1;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-119" target="FWEJ_FGA9GBXbfwohBE8-123" edge="1"> + <mxGeometry relative="1" as="geometry"> + <Array as="points"> + <mxPoint x="480" y="196" /> + <mxPoint x="480" y="360" /> + </Array> + </mxGeometry> </mxCell> - <mxCell id="V1Wl26Vbpgnno5Lb-wtg-35" value="data-db" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;spacing=-1;" parent="1" vertex="1"> - <mxGeometry x="407.5" y="613" width="85" height="20" as="geometry" /> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-118" value="HTTP" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="FWEJ_FGA9GBXbfwohBE8-117" vertex="1" connectable="0"> + <mxGeometry x="0.5551" y="-1" relative="1" as="geometry"> + <mxPoint x="1" y="-64" as="offset" /> + </mxGeometry> </mxCell> - <mxCell id="V1Wl26Vbpgnno5Lb-wtg-36" value="" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=8.600000000000023;fillColor=#E6E6E6;strokeColor=#000000;" parent="1" vertex="1"> - <mxGeometry x="250" y="550" width="50" height="64" as="geometry" /> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-119" value="<b>Gateway Service</b><div><i>nginx</i></div>" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#E6E6E6;fontColor=#000000;strokeColor=#000000;" parent="1" vertex="1"> + <mxGeometry x="520" y="176" width="130" height="40" as="geometry" /> </mxCell> - <mxCell id="V1Wl26Vbpgnno5Lb-wtg-37" value="auth-db" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;spacing=-1;" parent="1" vertex="1"> - <mxGeometry x="232.5" y="614" width="85" height="20" as="geometry" /> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-120" value="<b>Storage Service</b><div><i>seaweedfs</i></div>" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#E6E6E6;fontColor=#000000;strokeColor=#000000;" parent="1" vertex="1"> + <mxGeometry x="329.5" y="258" width="130" height="40" as="geometry" /> </mxCell> - <mxCell id="V1Wl26Vbpgnno5Lb-wtg-38" value="Storage Service<br>(SeaweedFS)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#E6E6E6;fontColor=#000000;strokeColor=#000000;" parent="1" vertex="1"> - <mxGeometry x="560" y="278" width="130" height="40" as="geometry" /> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-121" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;startArrow=classic;startFill=1;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-123" target="FWEJ_FGA9GBXbfwohBE8-120" edge="1"> + <mxGeometry relative="1" as="geometry" /> </mxCell> - <mxCell id="A18w2Y2_AVEIFkgUy5Lv-3" value="metadata-db-data" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;spacing=-1;" parent="1" vertex="1"> - <mxGeometry x="810.5" y="504" width="108" height="20" as="geometry" /> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-122" value="S3" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="FWEJ_FGA9GBXbfwohBE8-121" vertex="1" connectable="0"> + <mxGeometry x="0.0536" relative="1" as="geometry"> + <mxPoint y="1" as="offset" /> + </mxGeometry> </mxCell> - <mxCell id="A18w2Y2_AVEIFkgUy5Lv-6" value="" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;fillColor=#e1d5e7;strokeColor=#000000;" parent="1" vertex="1"> - <mxGeometry x="850.5" y="476" width="28" height="28" as="geometry" /> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-123" value="Analyse Service" style="rounded=1;whiteSpace=wrap;html=1;fontStyle=1" parent="1" vertex="1"> + <mxGeometry x="330" y="340" width="130" height="40" as="geometry" /> </mxCell> - <mxCell id="A18w2Y2_AVEIFkgUy5Lv-7" value="search-db-data" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;spacing=-1;" parent="1" vertex="1"> - <mxGeometry x="810.5" y="408" width="108" height="20" as="geometry" /> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-124" value="<b>Upload Service</b><div><i>tusd</i></div>" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#E6E6E6;fontColor=#000000;strokeColor=#000000;" parent="1" vertex="1"> + <mxGeometry x="330" y="176" width="130" height="40" as="geometry" /> </mxCell> - <mxCell id="A18w2Y2_AVEIFkgUy5Lv-9" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;entryPerimeter=0;" parent="1" source="A18w2Y2_AVEIFkgUy5Lv-8" target="V1Wl26Vbpgnno5Lb-wtg-26" edge="1"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-125" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;entryPerimeter=0;startArrow=classic;startFill=1;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-105" target="FWEJ_FGA9GBXbfwohBE8-106" edge="1"> <mxGeometry relative="1" as="geometry" /> </mxCell> - <mxCell id="A18w2Y2_AVEIFkgUy5Lv-8" value="" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;fillColor=#e1d5e7;strokeColor=#000000;" parent="1" vertex="1"> - <mxGeometry x="850.5" y="380" width="28" height="28" as="geometry" /> - </mxCell> - <mxCell id="A18w2Y2_AVEIFkgUy5Lv-10" value="data-db-data" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;spacing=-1;" parent="1" vertex="1"> - <mxGeometry x="394.5" y="684" width="108" height="20" as="geometry" /> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-126" value="HTTP" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="FWEJ_FGA9GBXbfwohBE8-125" vertex="1" connectable="0"> + <mxGeometry x="-0.0782" y="-1" relative="1" as="geometry"> + <mxPoint x="2" y="1" as="offset" /> + </mxGeometry> </mxCell> - <mxCell id="A18w2Y2_AVEIFkgUy5Lv-35" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="A18w2Y2_AVEIFkgUy5Lv-11" edge="1"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-127" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;startArrow=classic;startFill=1;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-128" target="FWEJ_FGA9GBXbfwohBE8-119" edge="1"> <mxGeometry relative="1" as="geometry"> - <mxPoint x="449" y="633" as="targetPoint" /> + <Array as="points"> + <mxPoint x="585" y="110" /> + </Array> </mxGeometry> </mxCell> - <mxCell id="A18w2Y2_AVEIFkgUy5Lv-11" value="" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;fillColor=#e1d5e7;strokeColor=#000000;" parent="1" vertex="1"> - <mxGeometry x="435" y="655" width="28" height="28" as="geometry" /> - </mxCell> - <mxCell id="A18w2Y2_AVEIFkgUy5Lv-34" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;" parent="1" source="A18w2Y2_AVEIFkgUy5Lv-15" target="V1Wl26Vbpgnno5Lb-wtg-37" edge="1"> - <mxGeometry relative="1" as="geometry" /> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-128" value="Researcher" style="shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;outlineConnect=0;" parent="1" vertex="1"> + <mxGeometry x="520" y="69" width="30" height="60" as="geometry" /> </mxCell> - <mxCell id="A18w2Y2_AVEIFkgUy5Lv-15" value="" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;fillColor=#e1d5e7;strokeColor=#000000;" parent="1" vertex="1"> - <mxGeometry x="261" y="656" width="28" height="28" as="geometry" /> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-129" value="Database<div>Engineer</div>" style="shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;outlineConnect=0;" parent="1" vertex="1"> + <mxGeometry x="490" y="586" width="30" height="60" as="geometry" /> </mxCell> - <mxCell id="A18w2Y2_AVEIFkgUy5Lv-16" value="auth-db-data" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;spacing=-1;" parent="1" vertex="1"> - <mxGeometry x="221" y="684" width="108" height="20" as="geometry" /> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-130" value="" style="rounded=0;whiteSpace=wrap;html=1;strokeColor=none;" parent="1" vertex="1"> + <mxGeometry x="540" y="550" width="420" height="14" as="geometry" /> </mxCell> - <mxCell id="YJRAzF6yD4Hh-bAvO1PB-2" value="JDBC" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;entryPerimeter=0;fontSize=9;" parent="1" source="YJRAzF6yD4Hh-bAvO1PB-1" target="V1Wl26Vbpgnno5Lb-wtg-34" edge="1"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-131" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;entryPerimeter=0;startArrow=classic;startFill=1;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-101" target="FWEJ_FGA9GBXbfwohBE8-113" edge="1"> <mxGeometry relative="1" as="geometry"> - <Array as="points" /> + <mxPoint x="840" y="524" as="sourcePoint" /> </mxGeometry> </mxCell> - <mxCell id="f61RwCrreTIYbJ5Vt7fi-14" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;startArrow=classic;startFill=1;" edge="1" parent="1" source="YJRAzF6yD4Hh-bAvO1PB-1" target="hBEam5F8n4ZBPeoiEcWH-1"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-132" value="HTTP" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="FWEJ_FGA9GBXbfwohBE8-131" vertex="1" connectable="0"> + <mxGeometry x="-0.0169" y="-1" relative="1" as="geometry"> + <mxPoint x="1" as="offset" /> + </mxGeometry> + </mxCell> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-133" value="JDBC" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;startArrow=classic;startFill=1;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-104" target="FWEJ_FGA9GBXbfwohBE8-111" edge="1"> <mxGeometry relative="1" as="geometry" /> </mxCell> - <mxCell id="YJRAzF6yD4Hh-bAvO1PB-1" value="Data Service" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1"> - <mxGeometry x="385" y="470" width="130" height="40" as="geometry" /> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-134" value="System<div>Engineer</div>" style="shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;outlineConnect=0;" parent="1" vertex="1"> + <mxGeometry x="662" y="571" width="30" height="60" as="geometry" /> </mxCell> - <mxCell id="V1Wl26Vbpgnno5Lb-wtg-27" value="search-db" style="text;html=1;strokeColor=none;fillColor=default;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;spacing=-1;" parent="1" vertex="1"> - <mxGeometry x="722.5" y="437" width="85" height="17" as="geometry" /> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-135" value="" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=8.600000000000023;fillColor=#E6E6E6;strokeColor=#000000;" parent="1" vertex="1"> + <mxGeometry x="339.5" y="584" width="50" height="64" as="geometry" /> </mxCell> - <mxCell id="OiuNRKl362wFz-YGv0-T-6" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=1;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="OiuNRKl362wFz-YGv0-T-7" edge="1"> - <mxGeometry relative="1" as="geometry"> - <mxPoint x="208" y="394" as="targetPoint" /> - </mxGeometry> - </mxCell> - <mxCell id="OiuNRKl362wFz-YGv0-T-7" value="" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;fillColor=#e1d5e7;strokeColor=#000000;" parent="1" vertex="1"> - <mxGeometry x="132" y="380" width="28" height="28" as="geometry" /> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-136" value="" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=8.600000000000023;fillColor=#E6E6E6;strokeColor=#000000;" parent="1" vertex="1"> + <mxGeometry x="399.5" y="584" width="50" height="64" as="geometry" /> </mxCell> - <mxCell id="OiuNRKl362wFz-YGv0-T-8" value="broker-service-data" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;spacing=-1;" parent="1" vertex="1"> - <mxGeometry x="93" y="408" width="108" height="20" as="geometry" /> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-137" value="" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=8.600000000000023;fillColor=#E6E6E6;strokeColor=#000000;" parent="1" vertex="1"> + <mxGeometry x="369.5" y="594" width="50" height="64" as="geometry" /> </mxCell> - <mxCell id="iy0HhJzZLXsiPmpU2ukH-7" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;entryPerimeter=0;" parent="1" source="iy0HhJzZLXsiPmpU2ukH-4" target="V1Wl26Vbpgnno5Lb-wtg-34" edge="1"> - <mxGeometry relative="1" as="geometry" /> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-138" value="" style="rounded=1;whiteSpace=wrap;html=1;fillColor=none;dashed=1;arcSize=6;" parent="1" vertex="1"> + <mxGeometry x="320" y="575" width="150" height="105" as="geometry" /> </mxCell> - <mxCell id="iy0HhJzZLXsiPmpU2ukH-4" value="Data DB Sidecar" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1"> - <mxGeometry x="560" y="563" width="130" height="40" as="geometry" /> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-139" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;dashed=1;entryX=1.004;entryY=0.397;entryDx=0;entryDy=0;entryPerimeter=0;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-129" target="FWEJ_FGA9GBXbfwohBE8-138" edge="1"> + <mxGeometry relative="1" as="geometry"> + <mxPoint x="460" y="616" as="targetPoint" /> + </mxGeometry> </mxCell> - <mxCell id="ZFea1dL5_0zV0EoV6Noq-2" value="Researcher" style="shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;outlineConnect=0;" parent="1" vertex="1"> - <mxGeometry x="347" y="553" width="30" height="60" as="geometry" /> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-140" value="User Interface" style="rounded=1;whiteSpace=wrap;html=1;fontStyle=1" parent="1" vertex="1"> + <mxGeometry x="710" y="340" width="130" height="40" as="geometry" /> </mxCell> - <mxCell id="ZFea1dL5_0zV0EoV6Noq-3" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;strokeColor=#000000;startArrow=classic;startFill=1;dashed=1;entryPerimeter=0;" parent="1" source="ZFea1dL5_0zV0EoV6Noq-2" target="V1Wl26Vbpgnno5Lb-wtg-34" edge="1"> - <mxGeometry x="-0.028" relative="1" as="geometry"> - <mxPoint x="458" y="240" as="sourcePoint" /> - <mxPoint as="offset" /> - <mxPoint x="458" y="288" as="targetPoint" /> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-141" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;startArrow=classic;startFill=1;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-142" target="FWEJ_FGA9GBXbfwohBE8-119" edge="1"> + <mxGeometry relative="1" as="geometry"> + <Array as="points"> + <mxPoint x="585" y="110" /> + </Array> </mxGeometry> </mxCell> - <mxCell id="iy0HhJzZLXsiPmpU2ukH-8" value="S3" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;startArrow=classic;startFill=1;jumpStyle=arc;" parent="1" source="V1Wl26Vbpgnno5Lb-wtg-38" target="iy0HhJzZLXsiPmpU2ukH-4" edge="1"> - <mxGeometry x="-0.4591" relative="1" as="geometry"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-142" value="Machine" style="shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;outlineConnect=0;" parent="1" vertex="1"> + <mxGeometry x="620" y="69" width="30" height="60" as="geometry" /> + </mxCell> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-143" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.25;entryY=1;entryDx=0;entryDy=0;jumpStyle=arc;startArrow=classic;startFill=1;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-85" target="FWEJ_FGA9GBXbfwohBE8-119" edge="1"> + <mxGeometry relative="1" as="geometry"> <Array as="points"> - <mxPoint x="810" y="298" /> - <mxPoint x="810" y="583" /> + <mxPoint x="395" y="480" /> + <mxPoint x="506" y="480" /> + <mxPoint x="506" y="410" /> + <mxPoint x="553" y="410" /> </Array> - <mxPoint as="offset" /> </mxGeometry> </mxCell> - <mxCell id="ZFea1dL5_0zV0EoV6Noq-4" value="" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#E1D5E7;" parent="1" vertex="1"> - <mxGeometry x="731" y="638" width="30" height="16" as="geometry" /> - </mxCell> - <mxCell id="ZFea1dL5_0zV0EoV6Noq-5" value="Docker volumes" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1"> - <mxGeometry x="768.5" y="638" width="92.5" height="16" as="geometry" /> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-144" value="HTTP" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="FWEJ_FGA9GBXbfwohBE8-143" vertex="1" connectable="0"> + <mxGeometry x="0.6707" relative="1" as="geometry"> + <mxPoint x="-1" as="offset" /> + </mxGeometry> </mxCell> - <mxCell id="ZFea1dL5_0zV0EoV6Noq-6" value="" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#E6E6E6;" parent="1" vertex="1"> - <mxGeometry x="731" y="658" width="30" height="16" as="geometry" /> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-145" value="" style="endArrow=none;dashed=1;html=1;rounded=0;entryX=1;entryY=0.976;entryDx=0;entryDy=0;entryPerimeter=0;exitX=1;exitY=0.076;exitDx=0;exitDy=0;exitPerimeter=0;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-80" target="FWEJ_FGA9GBXbfwohBE8-76" edge="1"> + <mxGeometry width="50" height="50" relative="1" as="geometry"> + <mxPoint x="810" y="570" as="sourcePoint" /> + <mxPoint x="860" y="520" as="targetPoint" /> + </mxGeometry> </mxCell> - <mxCell id="ZFea1dL5_0zV0EoV6Noq-7" value="Ext. maintained images" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1"> - <mxGeometry x="768.5" y="658" width="132.5" height="16" as="geometry" /> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-146" value="" style="endArrow=none;dashed=1;html=1;rounded=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;exitX=0;exitY=0.121;exitDx=0;exitDy=0;exitPerimeter=0;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-80" target="FWEJ_FGA9GBXbfwohBE8-130" edge="1"> + <mxGeometry width="50" height="50" relative="1" as="geometry"> + <mxPoint x="540" y="590" as="sourcePoint" /> + <mxPoint x="590" y="540" as="targetPoint" /> + </mxGeometry> </mxCell> - <mxCell id="f61RwCrreTIYbJ5Vt7fi-7" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;endArrow=none;endFill=0;startArrow=classic;startFill=1;" edge="1" parent="1" source="f61RwCrreTIYbJ5Vt7fi-3"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-147" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;startArrow=classic;startFill=1;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-119" target="FWEJ_FGA9GBXbfwohBE8-140" edge="1"> <mxGeometry relative="1" as="geometry"> - <mxPoint x="280" y="440" as="targetPoint" /> <Array as="points"> - <mxPoint x="95" y="440" /> + <mxPoint x="683" y="196" /> + <mxPoint x="683" y="360" /> </Array> </mxGeometry> </mxCell> - <mxCell id="f61RwCrreTIYbJ5Vt7fi-17" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;startArrow=classic;startFill=1;" edge="1" parent="1" source="f61RwCrreTIYbJ5Vt7fi-3" target="O_ELZSFbvl3Butg3bv_j-1"> - <mxGeometry relative="1" as="geometry" /> - </mxCell> - <mxCell id="f61RwCrreTIYbJ5Vt7fi-18" value="idp" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="f61RwCrreTIYbJ5Vt7fi-17"> - <mxGeometry x="-0.1676" y="1" relative="1" as="geometry"> - <mxPoint x="4" as="offset" /> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-148" value="HTTP" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="FWEJ_FGA9GBXbfwohBE8-147" vertex="1" connectable="0"> + <mxGeometry x="0.0179" relative="1" as="geometry"> + <mxPoint y="8" as="offset" /> </mxGeometry> </mxCell> - <mxCell id="f61RwCrreTIYbJ5Vt7fi-3" value="Identity Service<div>(OpenLDAP)</div>" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#E6E6E6;fontColor=#000000;strokeColor=#000000;" vertex="1" parent="1"> - <mxGeometry x="30" y="470" width="130" height="40" as="geometry" /> - </mxCell> - <mxCell id="f61RwCrreTIYbJ5Vt7fi-9" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;" edge="1" parent="1" source="f61RwCrreTIYbJ5Vt7fi-10"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-149" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.75;exitDx=0;exitDy=0;entryX=0;entryY=0.25;entryDx=0;entryDy=0;jumpStyle=arc;startArrow=classic;startFill=1;endArrow=none;endFill=0;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-105" target="FWEJ_FGA9GBXbfwohBE8-101" edge="1"> <mxGeometry relative="1" as="geometry"> - <mxPoint x="94" y="510" as="targetPoint" /> + <Array as="points"> + <mxPoint x="697" y="206" /> + <mxPoint x="697" y="514" /> + </Array> </mxGeometry> </mxCell> - <mxCell id="f61RwCrreTIYbJ5Vt7fi-10" value="" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;fillColor=#e1d5e7;strokeColor=#000000;" vertex="1" parent="1"> - <mxGeometry x="80" y="532" width="28" height="28" as="geometry" /> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-150" value="HTTP" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="FWEJ_FGA9GBXbfwohBE8-149" vertex="1" connectable="0"> + <mxGeometry x="-0.5289" y="-1" relative="1" as="geometry"> + <mxPoint x="4" y="34" as="offset" /> + </mxGeometry> + </mxCell> + <mxCell id="a_cl7nsyDpLQFaXOHeFD-5" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=1;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="a_cl7nsyDpLQFaXOHeFD-3" target="FWEJ_FGA9GBXbfwohBE8-108"> + <mxGeometry relative="1" as="geometry" /> + </mxCell> + <mxCell id="a_cl7nsyDpLQFaXOHeFD-6" value="HTTP" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="a_cl7nsyDpLQFaXOHeFD-5"> + <mxGeometry x="-0.1222" relative="1" as="geometry"> + <mxPoint as="offset" /> + </mxGeometry> </mxCell> - <mxCell id="f61RwCrreTIYbJ5Vt7fi-11" value="identity-service-data" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;spacing=-1;" vertex="1" parent="1"> - <mxGeometry x="40" y="561" width="108" height="20" as="geometry" /> + <mxCell id="a_cl7nsyDpLQFaXOHeFD-3" value="" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=8.600000000000023;fillColor=#E6E6E6;strokeColor=#000000;" vertex="1" parent="1"> + <mxGeometry x="900" y="410" width="50" height="64" as="geometry" /> </mxCell> - <mxCell id="f61RwCrreTIYbJ5Vt7fi-12" value="" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1"> - <mxGeometry x="731" y="678" width="30" height="16" as="geometry" /> + <mxCell id="a_cl7nsyDpLQFaXOHeFD-4" value="metric-db" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;spacing=-1;" vertex="1" parent="1"> + <mxGeometry x="882.5" y="474" width="85" height="17" as="geometry" /> </mxCell> - <mxCell id="f61RwCrreTIYbJ5Vt7fi-13" value="Maintained images" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1"> - <mxGeometry x="769.5" y="678" width="111.5" height="16" as="geometry" /> + <mxCell id="a_cl7nsyDpLQFaXOHeFD-7" value="* omitted edges for all services to metric-db" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1"> + <mxGeometry x="727" y="683" width="233" height="11" as="geometry" /> </mxCell> </root> </mxGraphModel> diff --git a/.docs/images/coverage.svg b/.docs/images/coverage.svg new file mode 100644 index 0000000000000000000000000000000000000000..8d22334eb1c46b39dbdbeb37ff93c218c188173d --- /dev/null +++ b/.docs/images/coverage.svg @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<svg xmlns="http://www.w3.org/2000/svg" width="124" height="20"> + <linearGradient id="b" x2="0" y2="100%"> + <stop offset="0" stop-color="#bbb" stop-opacity=".1"/> + <stop offset="1" stop-opacity=".1"/> + </linearGradient> + <mask id="anybadge_1"> + <rect width="124" height="20" rx="3" fill="#fff"/> + </mask> + <g mask="url(#anybadge_1)"> + <path fill="#555" d="M0 0h65v20H0z"/> + <path fill="#A9A9A9" d="M65 0h59v20H65z"/> + <path fill="url(#b)" d="M0 0h124v20H0z"/> + </g> + <g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11"> + <text x="33.5" y="15" fill="#010101" fill-opacity=".3">coverage</text> + <text x="32.5" y="14">coverage</text> + </g> + <g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11"> + <text x="95.5" y="15" fill="#010101" fill-opacity=".3">unknown</text> + <text x="94.5" y="14">unknown</text> + </g> +</svg> + diff --git a/.docs/images/pipeline.svg b/.docs/images/pipeline.svg new file mode 100644 index 0000000000000000000000000000000000000000..17f94998918fcb601111626a5436107abeaaa18f --- /dev/null +++ b/.docs/images/pipeline.svg @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<svg xmlns="http://www.w3.org/2000/svg" width="116" height="20"> + <linearGradient id="b" x2="0" y2="100%"> + <stop offset="0" stop-color="#bbb" stop-opacity=".1"/> + <stop offset="1" stop-opacity=".1"/> + </linearGradient> + <mask id="anybadge_1"> + <rect width="116" height="20" rx="3" fill="#fff"/> + </mask> + <g mask="url(#anybadge_1)"> + <path fill="#555" d="M0 0h57v20H0z"/> + <path fill="#A9A9A9" d="M57 0h59v20H57z"/> + <path fill="url(#b)" d="M0 0h116v20H0z"/> + </g> + <g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11"> + <text x="29.5" y="15" fill="#010101" fill-opacity=".3">pipeline</text> + <text x="28.5" y="14">pipeline</text> + </g> + <g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11"> + <text x="87.5" y="15" fill="#010101" fill-opacity=".3">unknown</text> + <text x="86.5" y="14">unknown</text> + </g> +</svg> + diff --git a/.docs/images/screenshots/grafana3.png b/.docs/images/screenshots/grafana3.png new file mode 100644 index 0000000000000000000000000000000000000000..f56be5d816a9c9a52046350f16a616adcf491596 Binary files /dev/null and b/.docs/images/screenshots/grafana3.png differ diff --git a/.docs/images/screenshots/grafana4.png b/.docs/images/screenshots/grafana4.png new file mode 100644 index 0000000000000000000000000000000000000000..30eee0259c2adb4e627ba9caa567f3cd55de411f Binary files /dev/null and b/.docs/images/screenshots/grafana4.png differ diff --git a/.docs/images/screenshots/grafana5.png b/.docs/images/screenshots/grafana5.png new file mode 100644 index 0000000000000000000000000000000000000000..36aae6b4ffc09808773d3705afd36815623d0161 Binary files /dev/null and b/.docs/images/screenshots/grafana5.png differ diff --git a/.docs/index.md b/.docs/index.md index d47bf06b2861569060235cf86bb13b58dd3eb046..f24d5c598e99e9a969b251cb0ba0854eb389f7a0 100644 --- a/.docs/index.md +++ b/.docs/index.md @@ -2,13 +2,13 @@ author: Martin Weise --- -[](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services){ tabindex=-1 } -[](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services){ tabindex=-1 } +[](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services){ tabindex=-1 } +[](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services){ tabindex=-1 } [](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services){ tabindex=-1 } [](https://hub.docker.com/u/dbrepo){ tabindex=-1 } [](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services){ tabindex=-1 } -Documentation for version: [v1.4.5](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/releases). +Documentation for version: [v1.4.7](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/releases). DBRepo is a repository for data in databases that are used from the beginning until the end of a research project supporting data evolution, -citation and -versioning. It implements the query store of the @@ -30,8 +30,13 @@ Installing DBRepo is very easy or ## Who is using DBRepo? - +- [TU Wien](https://dbrepo1.ec.tuwien.ac.at) +- TU Darmstadt +- [Universität Hamburg](https://dbrepo.fdm.uni-hamburg.de/) +- [Universiti Teknikal Malaysia Melaka](https://dbrepo.utem.edu.my/) +- University of the Philippines +- [Universiti Sains Malaysia](https://dbrepo.wrfexpress.com/) -## How can I try DBRepo +## How can I try DBRepo? [:fontawesome-solid-flask: Demonstration Instance](https://test.dbrepo.tuwien.ac.at){ .md-button .md-button--primary target="_blank" } \ No newline at end of file diff --git a/.docs/installation.md b/.docs/installation.md index 9c864ead4686a1b4c417147ad564740aeb5b8c8e..024d39bcd49cf68013c280552be3677bd8480e0a 100644 --- a/.docs/installation.md +++ b/.docs/installation.md @@ -11,7 +11,7 @@ author: Martin Weise If you have [Docker](https://docs.docker.com/engine/install/) already installed on your system, you can install DBRepo with: ```shell -curl -sSL https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/raw/release-1.4.5/install.sh | bash +curl -sSL https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/raw/release-1.4.7/install.sh | bash ``` !!! bug "Default installation security disclaimer" @@ -39,7 +39,7 @@ SSL/TLS certificate is recommended. Follow the [secure install](#secure-install) Execute the install script to download only the environment and save it to `dist`. ```shell -curl -sSL https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/raw/release-1.4.5/install.sh | DOWNLOAD_ONLY=1 bash +curl -sSL https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/raw/release-1.4.7/install.sh | DOWNLOAD_ONLY=1 bash ``` ### Static Configuration @@ -81,7 +81,7 @@ the variable `IDENTITY_SERVICE_ADMIN_PASSWORD` in `.env`. Update the client secret of the `dbrepo-client`: ```bash -curl -sSL "https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/raw/release-1.4.5/.scripts/reg-client-secret.sh" | bash +curl -sSL "https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/raw/release-1.4.7/.scripts/reg-client-secret.sh" | bash ``` Also, update the JWT key according to the diff --git a/.docs/kubernetes.md b/.docs/kubernetes.md index 04799b4edf3425f5ba46a7b0a1f140e092414ae0..2384f61d0451435b0515e09b128f71d942039bee 100644 --- a/.docs/kubernetes.md +++ b/.docs/kubernetes.md @@ -7,7 +7,7 @@ author: Martin Weise ## TL;DR To install DBRepo in your existing cluster, download the -sample [`values.yaml`](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/blob/release-1.4.5/helm/dbrepo/values.yaml) +sample [`values.yaml`](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/blob/release-1.4.7/helm/dbrepo/values.yaml) for your deployment and update the variables, especially `hostname`. ```shell @@ -15,41 +15,11 @@ helm upgrade --install dbrepo \ -n dbrepo \ "oci://registry.datalab.tuwien.ac.at/dbrepo/helm/dbrepo" \ --values ./values.yaml \ - --version "1.4.5" \ + --version "1.4.7" \ --create-namespace \ --cleanup-on-fail ``` -This chart is also on [Artifact Hub](https://artifacthub.io/packages/helm/dbrepo/dbrepo) with a full documentation -about values, etc. Before installing, you need to change credentials, e.g. the Broker Service administrator user -password: - -```yaml title="values.yaml" -brokerservice: - ... - auth: - ... - username: broker - password: broker - passwordHash: 1gwjNNTBPKLgyzbsUykfR0JIFC6nNqbNJaxzZ14uPT8JGcTZ -``` - -The `brokerservice.auth.passwordHash` field is the RabbitMQ SHA512-hash of the `brokerservice.auth.password` field and -can be obtained with -the [`generate-rabbitmq-pw.sh`](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/blob/release-1.4.5/helm/dbrepo/hack/generate-rabbitmq-pw.sh) -script: - -```console -$ ./generate-rabbitmq-pw.sh my_password -klPdmv4dgnRH64czHolIHAfXvc0G9hc24FQmPlI6eeI1NOf9 -``` - -The script needs the package `xxd` for generation of the random salt. If you don't have `xxd` installed, install it: - -* Debian/Ubuntu: `apt install xxd` -* Windows: `choco install xxd` -* MacOS: `brew install coreutils` - ## Prerequisites * Kubernetes 1.24+ @@ -58,9 +28,7 @@ The script needs the package `xxd` for generation of the random salt. If you don ## Limitations -1. MariaDB Galera does not (yet) support XA-transactions required by the authentication service (=Keycloak). Therefore - only a single MariaDB pod can be deployed at once for the Auth database. -2. The entire Helm deployment is rootless (=`runAsNonRoot=true`) except for +1. The entire Helm deployment is rootless (=`runAsNonRoot=true`) except for the [Storage Service](../api/storage-service) which still requires a root user. !!! question "Do you miss functionality? Do these limitations affect you?" diff --git a/.docs/redirect.html b/.docs/redirect.html index 4e513b2170628796d31b592b0e5b3190cfb0fe09..3f3b8027ad9b8493c62219288b8142c4e73aaea8 100644 --- a/.docs/redirect.html +++ b/.docs/redirect.html @@ -5,16 +5,16 @@ <head> <meta charset="UTF-8"> <title>Redirect Notice</title> - <meta http-equiv="Refresh" content="0; url='/infrastructures/dbrepo/1.4.5/'" /> + <meta http-equiv="Refresh" content="0; url='/infrastructures/dbrepo/1.4.7/'" /> </head> <body> <h1>Redirect Notice</h1> <p> - This page should automatically open the documentation for version <code>1.4.5</code>. In case this page does not load the site is + This page should automatically open the documentation for version <code>1.4.7</code>. In case this page does not load the site is available at: </p> <p> - <a href="/infrastructures/dbrepo/1.4.5/">/infrastructures/dbrepo/1.4.5/</a> + <a href="/infrastructures/dbrepo/1.4.7/">/infrastructures/dbrepo/1.4.7/</a> </p> </body> </html> \ No newline at end of file diff --git a/.env.unix.example b/.env.unix.example deleted file mode 100644 index cc42c2445172e19016c48e55a5a599df5961de38..0000000000000000000000000000000000000000 --- a/.env.unix.example +++ /dev/null @@ -1 +0,0 @@ -LOG_LEVEL=trace # error, warning, info, debug, trace \ No newline at end of file diff --git a/.gitignore b/.gitignore index 2e36c6ed89b2b75b83eb1cfd052448369e4a4e53..4d73111927df143b9e0d84fe70ef1dd9d570bc10 100644 --- a/.gitignore +++ b/.gitignore @@ -17,7 +17,8 @@ build/ tmp.yaml .docs/.swagger/api-* .scannerwork/ -.docker/config/* +.docker/config/ +.docker/dist.tar.gz # docs .docs/.swagger/dist/ @@ -26,6 +27,7 @@ site/ final/ .$* +dbrepo-somapper/ # Notebooks .pytest_cache/ diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 23b33f6ae2f31684d83717bd8a0ba9c8dac437f5..9721da7dae3ac1b35c0e09e2b1eeb775bd3ebecc 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -3,8 +3,8 @@ variables: DOCKER_HOST: "unix:///var/run/dind/docker.sock" TESTCONTAINERS_RYUK_DISABLED: "false" PYTHON_VERSION: "3.11" - APP_VERSION: "1.4.5" - CHART_VERSION: "1.4.5" + APP_VERSION: "1.4.7" + CHART_VERSION: "1.4.7" CACHE_FALLBACK_KEY: ${CI_DEFAULT_BRANCH} # This will supress any download for dependencies and plugins or upload messages which would clutter the console log. # `showDateTime` will show the passed time in milliseconds. You need to specify `--batch-mode` to make this work. @@ -35,9 +35,6 @@ stages: build-metadata-service: image: maven:3-openjdk-17 stage: build - except: - refs: - - /^release-.*/ script: - "mvn -f ./dbrepo-metadata-service/pom.xml clean install $MAVEN_OPTS -DskipTests" # Compiled classes are needed for SonarQube in later stages @@ -56,9 +53,6 @@ build-metadata-service: build-analyse-service: image: docker.io/pytorch/pytorch:2.4.0-cuda12.4-cudnn9-runtime stage: build - except: - refs: - - /^release-.*/ variables: PIPENV_PIPFILE: "./dbrepo-analyse-service/Pipfile" script: @@ -68,9 +62,6 @@ build-analyse-service: build-data-db-sidecar: image: docker.io/python:3.11-alpine stage: build - except: - refs: - - /^release-.*/ variables: PIPENV_PIPFILE: "./dbrepo-data-db/sidecar/Pipfile" script: @@ -80,9 +71,6 @@ build-data-db-sidecar: build-lib: image: docker.io/python:3.11-alpine stage: build - except: - refs: - - /^release-.*/ variables: PIPENV_PIPFILE: "./lib/python/Pipfile" script: @@ -92,9 +80,6 @@ build-lib: build-data-service: image: maven:3-openjdk-17 stage: build - except: - refs: - - /^release-.*/ needs: - build-metadata-service dependencies: @@ -112,20 +97,14 @@ build-data-service: expire_in: 1 days build-ui: - image: oven/bun:1.0.26-alpine + image: oven/bun:1.1.20-alpine stage: build - except: - refs: - - /^release-.*/ script: - "cd ./dbrepo-ui && bun install && bun run build" build-search-service: image: docker.io/python:3.11-alpine stage: build - except: - refs: - - /^release-.*/ script: - "pip install pipenv" - "cd dbrepo-search-service && pipenv install --system --deploy" @@ -133,13 +112,9 @@ build-search-service: build-docker: image: docker.io/docker:24-dind stage: build - except: - refs: - - /^release-.*/ before_script: - echo "$CI_REGISTRY_PASSWORD" | docker login --username "$CI_REGISTRY_USER" --password-stdin $CI_REGISTRY_URL script: - - "cp .env.unix.example .env" - "docker build -t dbrepo-metadata-service:build --target build dbrepo-metadata-service" - "docker build -t dbrepo-data-service:build --target build dbrepo-data-service" - "docker compose build --parallel" @@ -147,9 +122,6 @@ build-docker: build-helm: image: docker.io/docker:24-dind stage: build - except: - refs: - - /^release-.*/ before_script: - echo "$CI_GPG_KEYRING" | base64 -d > ./secring.gpg - echo "$CI_REGISTRY_PASSWORD" | docker login --username "$CI_REGISTRY_USER" --password-stdin $CI_REGISTRY_URL @@ -157,6 +129,39 @@ build-helm: - apk add sed helm curl - helm package ./helm/dbrepo --destination ./build +lint-docker-compose: + image: docker.io/alpine:3.18 + stage: lint + variables: + VERSION: 3.3.0 + BINARY: yq_linux_amd64 + before_script: + - 'apk --no-cache add bash wget' + - 'wget https://github.com/mikefarah/yq/releases/download/${VERSION}/${BINARY} -O /usr/bin/yq && chmod +x /usr/bin/yq' + - 'ls -la .scripts' + script: + - "yq compare -P docker-compose.yml .docker/docker-compose.yml 'volumes.*'" + - "IGNORE_IMAGE=1 IGNORE_PORTS=1 bash .scripts/check-service.sh 'dbrepo-analyse-service'" + - "bash .scripts/check-service.sh 'dbrepo-auth-db'" + - "IGNORE_IMAGE=1 IGNORE_PORTS=1 bash .scripts/check-service.sh 'dbrepo-auth-service'" + - "IGNORE_IMAGE=1 IGNORE_PORTS=1 bash .scripts/check-service.sh 'dbrepo-broker-service'" + - "IGNORE_PORTS=1 bash .scripts/check-service.sh 'dbrepo-dashboard-service'" + - "bash .scripts/check-service.sh 'dbrepo-data-db'" + - "IGNORE_IMAGE=1 IGNORE_PORTS=1 bash .scripts/check-service.sh 'dbrepo-data-db-sidecar'" + - "IGNORE_IMAGE=1 IGNORE_PORTS=1 bash .scripts/check-service.sh 'dbrepo-data-service'" + - "IGNORE_VOLUMES=1 bash .scripts/check-service.sh 'dbrepo-gateway-service'" + - "IGNORE_VOLUMES=1 bash .scripts/check-service.sh 'dbrepo-identity-service'" + - "IGNORE_VOLUMES=1 bash .scripts/check-service.sh 'dbrepo-metadata-db'" + - "IGNORE_IMAGE=1 IGNORE_PORTS=1 bash .scripts/check-service.sh 'dbrepo-metadata-service'" + - "IGNORE_VOLUMES=1 bash .scripts/check-service.sh 'dbrepo-metric-db'" + - "IGNORE_IMAGE=1 bash .scripts/check-service.sh 'dbrepo-search-db'" + - "IGNORE_IMAGE=1 IGNORE_PORTS=1 bash .scripts/check-service.sh 'dbrepo-search-service'" + - "IGNORE_IMAGE=1 bash .scripts/check-service.sh 'dbrepo-search-service-init'" + - "IGNORE_VOLUMES=1 bash .scripts/check-service.sh 'dbrepo-storage-service'" + - "IGNORE_VOLUMES=1 bash .scripts/check-service.sh 'dbrepo-storage-service-init'" + - "IGNORE_IMAGE=1 bash .scripts/check-service.sh 'dbrepo-ui'" + - "bash .scripts/check-service.sh 'dbrepo-upload-service'" + verify-install-script: image: docker.io/docker:24-dind stage: verify @@ -173,9 +178,6 @@ verify-install-script: lint-helm-chart: image: docker.io/alpine:3.20 stage: lint - except: - refs: - - /^release-.*/ needs: - build-metadata-service dependencies: @@ -188,9 +190,6 @@ lint-helm-chart: test-metadata-service: image: maven:3-openjdk-17 stage: test - except: - refs: - - /^release-.*/ needs: - build-metadata-service dependencies: @@ -211,9 +210,6 @@ test-metadata-service: test-data-service: image: maven:3-openjdk-17 stage: test - except: - refs: - - /^release-.*/ needs: - build-data-service dependencies: @@ -234,9 +230,6 @@ test-data-service: test-analyse-service: image: docker.io/python:3.11-alpine stage: test - except: - refs: - - /^release-.*/ variables: PIPENV_PIPFILE: "./dbrepo-analyse-service/Pipfile" needs: @@ -261,19 +254,43 @@ test-analyse-service: test-search-service: image: docker.io/python:3.11-alpine stage: test - except: - refs: - - /^release-.*/ variables: PIPENV_PIPFILE: "./dbrepo-search-service/Pipfile" needs: - build-search-service dependencies: - build-search-service + before_script: + - "cp -r ./dbrepo-search-service/init/clients ./dbrepo-search-service/clients" + - "cp -r ./dbrepo-search-service/init/omlib ./dbrepo-search-service/omlib" + script: + - "pip install pipenv" + - "pipenv install gunicorn && pipenv install --dev --system --deploy" + - cd ./dbrepo-search-service/ && coverage run -m pytest test/test_app.py test/test_jwt.py test/test_opensearch_client.py test/test_keycloak_client.py --junitxml=report.xml && coverage html && coverage report > ./coverage.txt + - "cat ./coverage.txt | grep -o 'TOTAL[^%]*%'" + artifacts: + when: always + paths: + - ./dbrepo-search-service/report.xml + - ./dbrepo-search-service/coverage.txt + expire_in: 1 days + reports: + junit: ./dbrepo-search-service/report.xml + coverage: '/TOTAL.*?([0-9]{1,3})%/' + +test-search-service-init: + image: docker.io/python:3.11-alpine + stage: test + variables: + PIPENV_PIPFILE: "./dbrepo-search-service/init/Pipfile" + needs: + - build-search-service + dependencies: + - build-search-service script: - "pip install pipenv" - "pipenv install gunicorn && pipenv install --dev --system --deploy" - - cd ./dbrepo-search-service/ && coverage run -m pytest test/test_opensearch_client.py --junitxml=report.xml && coverage html --omit="test/*,omlib/*" && coverage report --omit="test/*,omlib/*" > ./coverage.txt + - cd ./dbrepo-search-service/init/ && coverage run -m pytest test/test_app.py --junitxml=report.xml && coverage html && coverage report > ./coverage.txt - "cat ./coverage.txt | grep -o 'TOTAL[^%]*%'" artifacts: when: always @@ -288,9 +305,6 @@ test-search-service: test-lib: image: docker.io/python:3.11-alpine stage: test - except: - refs: - - /^release-.*/ variables: PIPENV_PIPFILE: "./lib/python/Pipfile" needs: @@ -312,6 +326,21 @@ test-lib: junit: ./lib/python/report.xml coverage: '/TOTAL.*?([0-9]{1,3})%/' +test-ui: + stage: test + image: docker.io/docker:24-dind + needs: + - build-ui + dependencies: + - build-ui + before_script: + - "apk add bash apache2-utils" + - "docker compose build dbrepo-ui" + - "docker run --name dbrepo-ui -e NODE_OPTIONS='--max_old_space_size=256' -p 3000:3000 -d dbrepo-ui:latest" + script: + - "sleep 30" + - "ENDPOINT=http://localhost:3000 bash ./dbrepo-ui/test/test_heap.sh" + scan-sonarqube: image: sonarsource/sonar-scanner-cli:10.0 stage: scan @@ -372,9 +401,6 @@ release-helm: refs: - /^release-.*/ when: manual - except: - refs: - - release-latest before_script: - "docker logout ${CI_REGISTRY_URL}" - "echo ${CI_REGISTRY_PASSWORD} | docker login --username ${CI_REGISTRY_USER} --password-stdin ${CI_REGISTRY_URL}" @@ -397,17 +423,19 @@ release-docs: refs: - /^release-.*/ before_script: - - "apk add --update alpine-sdk bash sed wget openssh" + - "apk add --update alpine-sdk bash sed wget openssh jq curl" - "pip install pipenv" - "pip install -r ./requirements.txt" - "mkdir -p ./final/${APP_VERSION}/rest" script: - - "make gen-lib-doc gen-docs-doc" + - "make gen-lib-doc gen-docs-doc package-config" - "cp -r ./lib/python/docs/build/html ./final/${APP_VERSION}/python" # sphinx - "cp .docs/.swagger/api.yaml ./final/${APP_VERSION}/rest/api.yaml" # swagger - "cp .docs/.swagger/swagger-ui.html ./final/${APP_VERSION}/rest/index.html" # swagger - "cp .docs/.swagger/custom.css ./final/${APP_VERSION}/rest/custom.css" # swagger - "cp -r ./site/* ./final/${APP_VERSION}" # mkdocs + - "cp .docker/dist.tar.gz ./final/${APP_VERSION}/dist.tar.gz" # dist + - "bash ./.gitlab/gen-badge.sh" - eval $(ssh-agent -s) - "mkdir -p /root/.ssh" - echo "$CI_KEY_PRIVATE" > /root/.ssh/id_rsa && chmod 0600 /root/.ssh/id_rsa diff --git a/.gitlab/gen-badge.sh b/.gitlab/gen-badge.sh new file mode 100644 index 0000000000000000000000000000000000000000..5ef15a3b6cafb7cf5324a8cbfed3383dd80aa4cf --- /dev/null +++ b/.gitlab/gen-badge.sh @@ -0,0 +1,11 @@ +#!/bin/bash +GITLAB_URL="https://gitlab.phaidra.org" +# if we reached this script, all the tests have passed +anybadge --label pipeline --value "passed" failed=red passed=green canceled=darkgray > "./final/${APP_VERSION}/images/pipeline.svg" +PIPELINE_COVERAGE=$(curl -fsSL -H "PRIVATE-TOKEN: ${CI_TOKEN}" "${GITLAB_URL}/api/v4/projects/450/pipelines/latest?ref=${CI_COMMIT_BRANCH}" | jq --raw-output .coverage) +echo "[INFO] pipeline coverage: ${PIPELINE_COVERAGE}" +if [ "${PIPELINE_COVERAGE}" != "null" ]; then + anybadge --label coverage --value "${PIPELINE_COVERAGE}" coverage > "./final/${APP_VERSION}/images/coverage.svg" +else + echo "[WARNING] Skipping badge generation, displaying default badge text: unknown" +fi diff --git a/.scripts/check-helm.sh b/.scripts/check-helm.sh new file mode 100755 index 0000000000000000000000000000000000000000..2233434029da0f89a672b9796317ac261bfa476a --- /dev/null +++ b/.scripts/check-helm.sh @@ -0,0 +1,6 @@ +#!/bin/bash +helm schema > /dev/null +if [ $? -ne 0 ]; then + echo "!!! Please install the Helm values schema plugin first\n" + echo " https://github.com/losisin/helm-values-schema-json" +fi diff --git a/.scripts/check-service.sh b/.scripts/check-service.sh new file mode 100755 index 0000000000000000000000000000000000000000..decc22312b8a44049d4675cc36a5be3e6aafe072 --- /dev/null +++ b/.scripts/check-service.sh @@ -0,0 +1,16 @@ +#!/bin/bash +yq compare -P docker-compose.yml .docker/docker-compose.yml "services.$1.restart" +yq compare -P docker-compose.yml .docker/docker-compose.yml "services.$1.container_name" +yq compare -P docker-compose.yml .docker/docker-compose.yml "services.$1.hostname" +if [ -z "$IGNORE_IMAGE" ]; then + yq compare -P docker-compose.yml .docker/docker-compose.yml "services.$1.image" +fi +if [ -z "$IGNORE_VOLUMES" ]; then + yq compare -P docker-compose.yml .docker/docker-compose.yml "services.$1.volumes" +fi +if [ -z "$IGNORE_PORTS" ]; then + yq compare -P docker-compose.yml .docker/docker-compose.yml "services.$1.ports" +fi +yq compare -P docker-compose.yml .docker/docker-compose.yml "services.$1.environment" +yq compare -P docker-compose.yml .docker/docker-compose.yml "services.$1.healthcheck" +yq compare -P docker-compose.yml .docker/docker-compose.yml "services.$1.logging" \ No newline at end of file diff --git a/Makefile b/Makefile index b279097f827becd26e3e39da0bbf866fd513516f..3300a5061d5b98e914c97dd0fc864a44970fd5de 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ .PHONY: all -APP_VERSION ?= 1.4.5 -CHART_VERSION ?= 1.4.5 +APP_VERSION ?= 1.4.7 +CHART_VERSION ?= 1.4.7 REPOSITORY_URL ?= registry.datalab.tuwien.ac.at/dbrepo .PHONY: all @@ -16,7 +16,6 @@ version: ## Get current version. @echo $(APP_VERSION) include make/build.mk -include make/dep.mk include make/dev.mk include make/gen.mk include make/rel.mk diff --git a/README.md b/README.md index e4f843507c43232f4817dbd562b49594d75d9385..06f03b60102d1e66c3a270807b3d23fee9c866c4 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ If you have [Docker](https://docs.docker.com/engine/install/) already installed with: ```bash -curl -sSL https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/raw/release-1.4.5/install.sh | bash +curl -sSL https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/raw/release-1.4.7/install.sh | bash ``` ## Documentation diff --git a/dbrepo-analyse-service/.gitignore b/dbrepo-analyse-service/.gitignore index 7c5690b1aaf83de1fae2cca50c6c3daecfa17f53..6663591e961d3056372d3b82d0534f6cbe1c19e5 100644 --- a/dbrepo-analyse-service/.gitignore +++ b/dbrepo-analyse-service/.gitignore @@ -18,6 +18,15 @@ venv/ .venv/ env* +# Libraries +./lib/dbrepo-1.4.4* +./lib/dbrepo-1.4.5* +./lib/dbrepo-1.4.6* +./lib/dbrepo-1.4.7rc* + +# LLM +*.bin + # Test report.xml coverage.html @@ -40,4 +49,4 @@ docs/_build/ htmlcov/ .coverage .coverage.* -*,cover \ No newline at end of file +*,cover diff --git a/dbrepo-analyse-service/Pipfile b/dbrepo-analyse-service/Pipfile index 1013236211f5f9541f0f5ce8ec9139e9bfe7bae4..4e91020afb0ce984c59d1c4cc0dc37ad52a857da 100644 --- a/dbrepo-analyse-service/Pipfile +++ b/dbrepo-analyse-service/Pipfile @@ -5,7 +5,6 @@ name = "pypi" [packages] boto3 = "*" -dbrepo = {path = "./lib/dbrepo-1.4.5.tar.gz"} exceptiongroup = "*" flasgger = "*" FlagEmbedding = "*" @@ -30,6 +29,8 @@ prometheus-flask-exporter = "*" pandas = "*" peft = "*" pydantic = "*" +dbrepo = {path = "./lib/dbrepo-1.4.7.tar.gz"} +opensearch-py = "*" textdistance = "*" torch = "*" diff --git a/dbrepo-analyse-service/Pipfile.lock b/dbrepo-analyse-service/Pipfile.lock index d5a8f80a627c491ea3221c2a5fdbfd285bb1ad15..bcff34a23efb2e4a660fb11c850aba569369e918 100644 --- a/dbrepo-analyse-service/Pipfile.lock +++ b/dbrepo-analyse-service/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "5029f33bd9b8140e06819e4a3f08b1b9b757b309c6d284758de01011e027920e" + "sha256": "9e1fb16b1632a76b8a2fb6ac372b92556c573a7246bd37dd32813559bb27c8d9" }, "pipfile-spec": 6, "requires": { @@ -16,118 +16,110 @@ ] }, "default": { - "accelerate": { - "hashes": [ - "sha256:0a7f33d60ba09afabd028d4f0856dd19c5a734b7a596d637d9dd6e3d0eadbaf3", - "sha256:11ba481ed6ea09191775df55ce464aeeba67a024bd0261a44b77b30fb439e26a" - ], - "markers": "python_full_version >= '3.8.0'", - "version": "==0.33.0" - }, "aiohappyeyeballs": { "hashes": [ - "sha256:55a1714f084e63d49639800f95716da97a1f173d46a16dfcfda0016abb93b6b2", - "sha256:7ce92076e249169a13c2f49320d1967425eaf1f407522d707d59cac7628d62bd" + "sha256:75cf88a15106a5002a8eb1dab212525c00d1f4c0fa96e551c9fbe6f09a621586", + "sha256:8a7a83727b2756f394ab2895ea0765a0a8c475e3c71e98d43d76f22b4b435572" ], "markers": "python_version >= '3.8'", - "version": "==2.4.0" + "version": "==2.4.3" }, "aiohttp": { "hashes": [ - "sha256:02594361128f780eecc2a29939d9dfc870e17b45178a867bf61a11b2a4367277", - "sha256:03f2645adbe17f274444953bdea69f8327e9d278d961d85657cb0d06864814c1", - "sha256:074d1bff0163e107e97bd48cad9f928fa5a3eb4b9d33366137ffce08a63e37fe", - "sha256:0912b8a8fadeb32ff67a3ed44249448c20148397c1ed905d5dac185b4ca547bb", - "sha256:0d277cfb304118079e7044aad0b76685d30ecb86f83a0711fc5fb257ffe832ca", - "sha256:0d93400c18596b7dc4794d48a63fb361b01a0d8eb39f28800dc900c8fbdaca91", - "sha256:123dd5b16b75b2962d0fff566effb7a065e33cd4538c1692fb31c3bda2bfb972", - "sha256:17e997105bd1a260850272bfb50e2a328e029c941c2708170d9d978d5a30ad9a", - "sha256:18a01eba2574fb9edd5f6e5fb25f66e6ce061da5dab5db75e13fe1558142e0a3", - "sha256:1923a5c44061bffd5eebeef58cecf68096e35003907d8201a4d0d6f6e387ccaa", - "sha256:1942244f00baaacaa8155eca94dbd9e8cc7017deb69b75ef67c78e89fdad3c77", - "sha256:1b2c16a919d936ca87a3c5f0e43af12a89a3ce7ccbce59a2d6784caba945b68b", - "sha256:1c19de68896747a2aa6257ae4cf6ef59d73917a36a35ee9d0a6f48cff0f94db8", - "sha256:1e72589da4c90337837fdfe2026ae1952c0f4a6e793adbbfbdd40efed7c63599", - "sha256:22c0a23a3b3138a6bf76fc553789cb1a703836da86b0f306b6f0dc1617398abc", - "sha256:2c634a3207a5445be65536d38c13791904fda0748b9eabf908d3fe86a52941cf", - "sha256:2d21ac12dc943c68135ff858c3a989f2194a709e6e10b4c8977d7fcd67dfd511", - "sha256:2f1f1c75c395991ce9c94d3e4aa96e5c59c8356a15b1c9231e783865e2772699", - "sha256:305be5ff2081fa1d283a76113b8df7a14c10d75602a38d9f012935df20731487", - "sha256:33e6bc4bab477c772a541f76cd91e11ccb6d2efa2b8d7d7883591dfb523e5987", - "sha256:349ef8a73a7c5665cca65c88ab24abe75447e28aa3bc4c93ea5093474dfdf0ff", - "sha256:380f926b51b92d02a34119d072f178d80bbda334d1a7e10fa22d467a66e494db", - "sha256:38172a70005252b6893088c0f5e8a47d173df7cc2b2bd88650957eb84fcf5022", - "sha256:391cc3a9c1527e424c6865e087897e766a917f15dddb360174a70467572ac6ce", - "sha256:3a1c32a19ee6bbde02f1cb189e13a71b321256cc1d431196a9f824050b160d5a", - "sha256:4120d7fefa1e2d8fb6f650b11489710091788de554e2b6f8347c7a20ceb003f5", - "sha256:424ae21498790e12eb759040bbb504e5e280cab64693d14775c54269fd1d2bb7", - "sha256:44b324a6b8376a23e6ba25d368726ee3bc281e6ab306db80b5819999c737d820", - "sha256:4790f0e15f00058f7599dab2b206d3049d7ac464dc2e5eae0e93fa18aee9e7bf", - "sha256:4aff049b5e629ef9b3e9e617fa6e2dfeda1bf87e01bcfecaf3949af9e210105e", - "sha256:4b38b1570242fbab8d86a84128fb5b5234a2f70c2e32f3070143a6d94bc854cf", - "sha256:4d46c7b4173415d8e583045fbc4daa48b40e31b19ce595b8d92cf639396c15d5", - "sha256:4f1c9866ccf48a6df2b06823e6ae80573529f2af3a0992ec4fe75b1a510df8a6", - "sha256:4f7acae3cf1a2a2361ec4c8e787eaaa86a94171d2417aae53c0cca6ca3118ff6", - "sha256:54d9ddea424cd19d3ff6128601a4a4d23d54a421f9b4c0fff740505813739a91", - "sha256:58718e181c56a3c02d25b09d4115eb02aafe1a732ce5714ab70326d9776457c3", - "sha256:5ede29d91a40ba22ac1b922ef510aab871652f6c88ef60b9dcdf773c6d32ad7a", - "sha256:61645818edd40cc6f455b851277a21bf420ce347baa0b86eaa41d51ef58ba23d", - "sha256:66bf9234e08fe561dccd62083bf67400bdbf1c67ba9efdc3dac03650e97c6088", - "sha256:673f988370f5954df96cc31fd99c7312a3af0a97f09e407399f61583f30da9bc", - "sha256:676f94c5480d8eefd97c0c7e3953315e4d8c2b71f3b49539beb2aa676c58272f", - "sha256:6c225286f2b13bab5987425558baa5cbdb2bc925b2998038fa028245ef421e75", - "sha256:7384d0b87d4635ec38db9263e6a3f1eb609e2e06087f0aa7f63b76833737b471", - "sha256:7e2fe37ac654032db1f3499fe56e77190282534810e2a8e833141a021faaab0e", - "sha256:7f2bfc0032a00405d4af2ba27f3c429e851d04fad1e5ceee4080a1c570476697", - "sha256:7f6b639c36734eaa80a6c152a238242bedcee9b953f23bb887e9102976343092", - "sha256:814375093edae5f1cb31e3407997cf3eacefb9010f96df10d64829362ae2df69", - "sha256:8224f98be68a84b19f48e0bdc14224b5a71339aff3a27df69989fa47d01296f3", - "sha256:898715cf566ec2869d5cb4d5fb4be408964704c46c96b4be267442d265390f32", - "sha256:8989f46f3d7ef79585e98fa991e6ded55d2f48ae56d2c9fa5e491a6e4effb589", - "sha256:8ba01ebc6175e1e6b7275c907a3a36be48a2d487549b656aa90c8a910d9f3178", - "sha256:8c5c6fa16412b35999320f5c9690c0f554392dc222c04e559217e0f9ae244b92", - "sha256:8c6a4e5e40156d72a40241a25cc226051c0a8d816610097a8e8f517aeacd59a2", - "sha256:8eaf44ccbc4e35762683078b72bf293f476561d8b68ec8a64f98cf32811c323e", - "sha256:8fb4fc029e135859f533025bc82047334e24b0d489e75513144f25408ecaf058", - "sha256:9093a81e18c45227eebe4c16124ebf3e0d893830c6aca7cc310bfca8fe59d857", - "sha256:94c4381ffba9cc508b37d2e536b418d5ea9cfdc2848b9a7fea6aebad4ec6aac1", - "sha256:94fac7c6e77ccb1ca91e9eb4cb0ac0270b9fb9b289738654120ba8cebb1189c6", - "sha256:95c4dc6f61d610bc0ee1edc6f29d993f10febfe5b76bb470b486d90bbece6b22", - "sha256:975218eee0e6d24eb336d0328c768ebc5d617609affaca5dbbd6dd1984f16ed0", - "sha256:ad146dae5977c4dd435eb31373b3fe9b0b1bf26858c6fc452bf6af394067e10b", - "sha256:afe16a84498441d05e9189a15900640a2d2b5e76cf4efe8cbb088ab4f112ee57", - "sha256:b1c43eb1ab7cbf411b8e387dc169acb31f0ca0d8c09ba63f9eac67829585b44f", - "sha256:b90078989ef3fc45cf9221d3859acd1108af7560c52397ff4ace8ad7052a132e", - "sha256:b98e698dc34966e5976e10bbca6d26d6724e6bdea853c7c10162a3235aba6e16", - "sha256:ba5a8b74c2a8af7d862399cdedce1533642fa727def0b8c3e3e02fcb52dca1b1", - "sha256:c31ad0c0c507894e3eaa843415841995bf8de4d6b2d24c6e33099f4bc9fc0d4f", - "sha256:c3b9162bab7e42f21243effc822652dc5bb5e8ff42a4eb62fe7782bcbcdfacf6", - "sha256:c58c6837a2c2a7cf3133983e64173aec11f9c2cd8e87ec2fdc16ce727bcf1a04", - "sha256:c83f7a107abb89a227d6c454c613e7606c12a42b9a4ca9c5d7dad25d47c776ae", - "sha256:cde98f323d6bf161041e7627a5fd763f9fd829bcfcd089804a5fdce7bb6e1b7d", - "sha256:ce91db90dbf37bb6fa0997f26574107e1b9d5ff939315247b7e615baa8ec313b", - "sha256:d00f3c5e0d764a5c9aa5a62d99728c56d455310bcc288a79cab10157b3af426f", - "sha256:d17920f18e6ee090bdd3d0bfffd769d9f2cb4c8ffde3eb203777a3895c128862", - "sha256:d55f011da0a843c3d3df2c2cf4e537b8070a419f891c930245f05d329c4b0689", - "sha256:d742c36ed44f2798c8d3f4bc511f479b9ceef2b93f348671184139e7d708042c", - "sha256:d9a487ef090aea982d748b1b0d74fe7c3950b109df967630a20584f9a99c0683", - "sha256:d9ef084e3dc690ad50137cc05831c52b6ca428096e6deb3c43e95827f531d5ef", - "sha256:da452c2c322e9ce0cfef392e469a26d63d42860f829026a63374fde6b5c5876f", - "sha256:dc4826823121783dccc0871e3f405417ac116055bf184ac04c36f98b75aacd12", - "sha256:de7a5299827253023c55ea549444e058c0eb496931fa05d693b95140a947cb73", - "sha256:e04a1f2a65ad2f93aa20f9ff9f1b672bf912413e5547f60749fa2ef8a644e061", - "sha256:e1ca1ef5ba129718a8fc827b0867f6aa4e893c56eb00003b7367f8a733a9b072", - "sha256:ee40b40aa753d844162dcc80d0fe256b87cba48ca0054f64e68000453caead11", - "sha256:f071854b47d39591ce9a17981c46790acb30518e2f83dfca8db2dfa091178691", - "sha256:f29930bc2921cef955ba39a3ff87d2c4398a0394ae217f41cb02d5c26c8b1b77", - "sha256:f489a2c9e6455d87eabf907ac0b7d230a9786be43fbe884ad184ddf9e9c1e385", - "sha256:f5bf3ead3cb66ab990ee2561373b009db5bc0e857549b6c9ba84b20bc462e172", - "sha256:f6f18898ace4bcd2d41a122916475344a87f1dfdec626ecde9ee802a711bc569", - "sha256:f8112fb501b1e0567a1251a2fd0747baae60a4ab325a871e975b7bb67e59221f", - "sha256:fd31f176429cecbc1ba499d4aba31aaccfea488f418d60376b911269d3b883c5" + "sha256:007ec22fbc573e5eb2fb7dec4198ef8f6bf2fe4ce20020798b2eb5d0abda6138", + "sha256:00819de9e45d42584bed046314c40ea7e9aea95411b38971082cad449392b08c", + "sha256:01948b1d570f83ee7bbf5a60ea2375a89dfb09fd419170e7f5af029510033d24", + "sha256:038f514fe39e235e9fef6717fbf944057bfa24f9b3db9ee551a7ecf584b5b480", + "sha256:03a42ac7895406220124c88911ebee31ba8b2d24c98507f4a8bf826b2937c7f2", + "sha256:05646ebe6b94cc93407b3bf34b9eb26c20722384d068eb7339de802154d61bc5", + "sha256:0631dd7c9f0822cc61c88586ca76d5b5ada26538097d0f1df510b082bad3411a", + "sha256:0b00807e2605f16e1e198f33a53ce3c4523114059b0c09c337209ae55e3823a8", + "sha256:0e1b370d8007c4ae31ee6db7f9a2fe801a42b146cec80a86766e7ad5c4a259cf", + "sha256:15ecd889a709b0080f02721255b3f80bb261c2293d3c748151274dfea93ac871", + "sha256:1b66ccafef7336a1e1f0e389901f60c1d920102315a56df85e49552308fc0486", + "sha256:1bbb122c557a16fafc10354b9d99ebf2f2808a660d78202f10ba9d50786384b9", + "sha256:1eb89d3d29adaf533588f209768a9c02e44e4baf832b08118749c5fad191781d", + "sha256:258c5dd01afc10015866114e210fb7365f0d02d9d059c3c3415382ab633fcbcb", + "sha256:2609e9ab08474702cc67b7702dbb8a80e392c54613ebe80db7e8dbdb79837c68", + "sha256:274cfa632350225ce3fdeb318c23b4a10ec25c0e2c880eff951a3842cf358ac1", + "sha256:28529e08fde6f12eba8677f5a8608500ed33c086f974de68cc65ab218713a59d", + "sha256:2b606353da03edcc71130b52388d25f9a30a126e04caef1fd637e31683033abd", + "sha256:30ca7c3b94708a9d7ae76ff281b2f47d8eaf2579cd05971b5dc681db8caac6e1", + "sha256:333cf6cf8e65f6a1e06e9eb3e643a0c515bb850d470902274239fea02033e9a8", + "sha256:3455522392fb15ff549d92fbf4b73b559d5e43dc522588f7eb3e54c3f38beee7", + "sha256:362f641f9071e5f3ee6f8e7d37d5ed0d95aae656adf4ef578313ee585b585959", + "sha256:3bcd391d083f636c06a68715e69467963d1f9600f85ef556ea82e9ef25f043f7", + "sha256:3dffb610a30d643983aeb185ce134f97f290f8935f0abccdd32c77bed9388b42", + "sha256:3fe407bf93533a6fa82dece0e74dbcaaf5d684e5a51862887f9eaebe6372cd79", + "sha256:413251f6fcf552a33c981c4709a6bba37b12710982fec8e558ae944bfb2abd38", + "sha256:438cd072f75bb6612f2aca29f8bd7cdf6e35e8f160bc312e49fbecab77c99e3a", + "sha256:4470c73c12cd9109db8277287d11f9dd98f77fc54155fc71a7738a83ffcc8ea8", + "sha256:45c3b868724137f713a38376fef8120c166d1eadd50da1855c112fe97954aed8", + "sha256:486f7aabfa292719a2753c016cc3a8f8172965cabb3ea2e7f7436c7f5a22a151", + "sha256:4f05e9727ce409358baa615dbeb9b969db94324a79b5a5cea45d39bdb01d82e6", + "sha256:50aed5155f819873d23520919e16703fc8925e509abbb1a1491b0087d1cd969e", + "sha256:50edbcad60d8f0e3eccc68da67f37268b5144ecc34d59f27a02f9611c1d4eec7", + "sha256:54ca74df1be3c7ca1cf7f4c971c79c2daf48d9aa65dea1a662ae18926f5bc8ce", + "sha256:578a4b875af3e0daaf1ac6fa983d93e0bbfec3ead753b6d6f33d467100cdc67b", + "sha256:597a079284b7ee65ee102bc3a6ea226a37d2b96d0418cc9047490f231dc09fe8", + "sha256:59bb3c54aa420521dc4ce3cc2c3fe2ad82adf7b09403fa1f48ae45c0cbde6628", + "sha256:5c6a5b8c7926ba5d8545c7dd22961a107526562da31a7a32fa2456baf040939f", + "sha256:64f6c17757251e2b8d885d728b6433d9d970573586a78b78ba8929b0f41d045a", + "sha256:679abe5d3858b33c2cf74faec299fda60ea9de62916e8b67e625d65bf069a3b7", + "sha256:741a46d58677d8c733175d7e5aa618d277cd9d880301a380fd296975a9cdd7bc", + "sha256:7789050d9e5d0c309c706953e5e8876e38662d57d45f936902e176d19f1c58ab", + "sha256:77abf6665ae54000b98b3c742bc6ea1d1fb31c394bcabf8b5d2c1ac3ebfe7f3b", + "sha256:79019094f87c9fb44f8d769e41dbb664d6e8fcfd62f665ccce36762deaa0e911", + "sha256:7b06b7843929e41a94ea09eb1ce3927865387e3e23ebe108e0d0d09b08d25be9", + "sha256:7e338c0523d024fad378b376a79faff37fafb3c001872a618cde1d322400a572", + "sha256:7ea7ffc6d6d6f8a11e6f40091a1040995cdff02cfc9ba4c2f30a516cb2633554", + "sha256:8105fd8a890df77b76dd3054cddf01a879fc13e8af576805d667e0fa0224c35d", + "sha256:84afcdea18eda514c25bc68b9af2a2b1adea7c08899175a51fe7c4fb6d551257", + "sha256:9294bbb581f92770e6ed5c19559e1e99255e4ca604a22c5c6397b2f9dd3ee42c", + "sha256:93429602396f3383a797a2a70e5f1de5df8e35535d7806c9f91df06f297e109b", + "sha256:9627cc1a10c8c409b5822a92d57a77f383b554463d1884008e051c32ab1b3742", + "sha256:998f3bd3cfc95e9424a6acd7840cbdd39e45bc09ef87533c006f94ac47296090", + "sha256:9c72109213eb9d3874f7ac8c0c5fa90e072d678e117d9061c06e30c85b4cf0e6", + "sha256:9fc1500fd2a952c5c8e3b29aaf7e3cc6e27e9cfc0a8819b3bce48cc1b849e4cc", + "sha256:a3f00003de6eba42d6e94fabb4125600d6e484846dbf90ea8e48a800430cc142", + "sha256:a45d85cf20b5e0d0aa5a8dca27cce8eddef3292bc29d72dcad1641f4ed50aa16", + "sha256:a7d8d14fe962153fc681f6366bdec33d4356f98a3e3567782aac1b6e0e40109a", + "sha256:a8fa23fe62c436ccf23ff930149c047f060c7126eae3ccea005f0483f27b2e28", + "sha256:aa6658732517ddabe22c9036479eabce6036655ba87a0224c612e1ae6af2087e", + "sha256:aafc8ee9b742ce75044ae9a4d3e60e3d918d15a4c2e08a6c3c3e38fa59b92d94", + "sha256:ab5a5a0c7a7991d90446a198689c0535be89bbd6b410a1f9a66688f0880ec026", + "sha256:acd48d5b80ee80f9432a165c0ac8cbf9253eaddb6113269a5e18699b33958dbb", + "sha256:ad7593bb24b2ab09e65e8a1d385606f0f47c65b5a2ae6c551db67d6653e78c28", + "sha256:baa42524a82f75303f714108fea528ccacf0386af429b69fff141ffef1c534f9", + "sha256:bdfcf6443637c148c4e1a20c48c566aa694fa5e288d34b20fcdc58507882fed3", + "sha256:be7443669ae9c016b71f402e43208e13ddf00912f47f623ee5994e12fc7d4b3f", + "sha256:c02a30b904282777d872266b87b20ed8cc0d1501855e27f831320f471d54d983", + "sha256:c1277cd707c465cd09572a774559a3cc7c7a28802eb3a2a9472588f062097205", + "sha256:c30a0eafc89d28e7f959281b58198a9fa5e99405f716c0289b7892ca345fe45f", + "sha256:c5ce2ce7c997e1971b7184ee37deb6ea9922ef5163c6ee5aa3c274b05f9e12fa", + "sha256:c823bc3971c44ab93e611ab1a46b1eafeae474c0c844aff4b7474287b75fe49c", + "sha256:ce0cdc074d540265bfeb31336e678b4e37316849d13b308607efa527e981f5c2", + "sha256:d1720b4f14c78a3089562b8875b53e36b51c97c51adc53325a69b79b4b48ebcb", + "sha256:d183cf9c797a5291e8301790ed6d053480ed94070637bfaad914dd38b0981f67", + "sha256:d9010c31cd6fa59438da4e58a7f19e4753f7f264300cd152e7f90d4602449762", + "sha256:d9e5e4a85bdb56d224f412d9c98ae4cbd032cc4f3161818f692cd81766eee65a", + "sha256:da1dee8948d2137bb51fbb8a53cce6b1bcc86003c6b42565f008438b806cccd8", + "sha256:df9270660711670e68803107d55c2b5949c2e0f2e4896da176e1ecfc068b974a", + "sha256:e00e3505cd80440f6c98c6d69269dcc2a119f86ad0a9fd70bccc59504bebd68a", + "sha256:e48d5021a84d341bcaf95c8460b152cfbad770d28e5fe14a768988c461b821bc", + "sha256:e7f8b04d83483577fd9200461b057c9f14ced334dcb053090cea1da9c8321a91", + "sha256:edfe3341033a6b53a5c522c802deb2079eee5cbfbb0af032a55064bd65c73a23", + "sha256:ef9c33cc5cbca35808f6c74be11eb7f5f6b14d2311be84a15b594bd3e58b5527", + "sha256:f2d4324a98062be0525d16f768a03e0bbb3b9fe301ceee99611dc9a7953124e6", + "sha256:f3935f82f6f4a3820270842e90456ebad3af15810cf65932bd24da4463bc0a4c", + "sha256:f614ab0c76397661b90b6851a030004dac502e48260ea10f2441abd2207fbcc7", + "sha256:f7db54c7914cc99d901d93a34704833568d86c20925b2762f9fa779f9cd2e70f", + "sha256:fbc6264158392bad9df19537e872d476f7c57adf718944cc1e4495cbabf38e2a", + "sha256:fe2fb38c2ed905a2582948e2de560675e9dfbee94c6d5ccdb1301c6d0a5bf092", + "sha256:ffe595f10566f8276b76dc3a11ae4bb7eba1aac8ddd75811736a15b0d5311414" ], "markers": "python_version >= '3.8'", - "version": "==3.10.5" + "version": "==3.10.10" }, "aiosignal": { "hashes": [ @@ -198,205 +190,212 @@ }, "boto3": { "hashes": [ - "sha256:c2f0837a259002489e59d1c30008791e3b3bb59e30e48c64e1d2d270147a4549", - "sha256:cbf197ce28f04bc1ffa1db0aa26a1903d9bfa57a490f70537932e84367cdd15b" + "sha256:5970b62c1ec8177501e02520f0d41839ca5fc549b30bac4e8c0c0882ae776217", + "sha256:670f811c65e3c5fe4ed8c8d69be0b44b1d649e992c0fc16de43816d1188f88f1" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==1.35.2" + "version": "==1.35.39" }, "botocore": { "hashes": [ - "sha256:92b168d8be79055bb25754aa34d699866d8aa66abc69f8ce99b0c191bd9c6e70", - "sha256:96c8eb6f0baed623a1b57ca9f24cb21d5508872cf0dfebb55527a85b6dbc76ba" + "sha256:781c547eb6a79c0e4b0bedd87b81fbfed957816b4841d33e20c8f1989c7c19ce", + "sha256:cb7f851933b5ccc2fba4f0a8b846252410aa0efac5bfbe93b82d10801f5f8e90" ], "markers": "python_version >= '3.8'", - "version": "==1.35.2" - }, - "cachelib": { - "hashes": [ - "sha256:38222cc7c1b79a23606de5c2607f4925779e37cdcea1c2ad21b8bae94b5425a5", - "sha256:811ceeb1209d2fe51cd2b62810bd1eccf70feba5c52641532498be5c675493b3" - ], - "markers": "python_version >= '3.7'", - "version": "==0.9.0" + "version": "==1.35.39" }, "certifi": { "hashes": [ - "sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b", - "sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90" + "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8", + "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9" ], "markers": "python_version >= '3.6'", - "version": "==2024.7.4" + "version": "==2024.8.30" }, "cffi": { "hashes": [ - "sha256:011aff3524d578a9412c8b3cfaa50f2c0bd78e03eb7af7aa5e0df59b158efb2f", - "sha256:0a048d4f6630113e54bb4b77e315e1ba32a5a31512c31a273807d0027a7e69ab", - "sha256:0bb15e7acf8ab35ca8b24b90af52c8b391690ef5c4aec3d31f38f0d37d2cc499", - "sha256:0d46ee4764b88b91f16661a8befc6bfb24806d885e27436fdc292ed7e6f6d058", - "sha256:0e60821d312f99d3e1569202518dddf10ae547e799d75aef3bca3a2d9e8ee693", - "sha256:0fdacad9e0d9fc23e519efd5ea24a70348305e8d7d85ecbb1a5fa66dc834e7fb", - "sha256:14b9cbc8f7ac98a739558eb86fabc283d4d564dafed50216e7f7ee62d0d25377", - "sha256:17c6d6d3260c7f2d94f657e6872591fe8733872a86ed1345bda872cfc8c74885", - "sha256:1a2ddbac59dc3716bc79f27906c010406155031a1c801410f1bafff17ea304d2", - "sha256:2404f3de742f47cb62d023f0ba7c5a916c9c653d5b368cc966382ae4e57da401", - "sha256:24658baf6224d8f280e827f0a50c46ad819ec8ba380a42448e24459daf809cf4", - "sha256:24aa705a5f5bd3a8bcfa4d123f03413de5d86e497435693b638cbffb7d5d8a1b", - "sha256:2770bb0d5e3cc0e31e7318db06efcbcdb7b31bcb1a70086d3177692a02256f59", - "sha256:331ad15c39c9fe9186ceaf87203a9ecf5ae0ba2538c9e898e3a6967e8ad3db6f", - "sha256:3aa9d43b02a0c681f0bfbc12d476d47b2b2b6a3f9287f11ee42989a268a1833c", - "sha256:41f4915e09218744d8bae14759f983e466ab69b178de38066f7579892ff2a555", - "sha256:4304d4416ff032ed50ad6bb87416d802e67139e31c0bde4628f36a47a3164bfa", - "sha256:435a22d00ec7d7ea533db494da8581b05977f9c37338c80bc86314bec2619424", - "sha256:45f7cd36186db767d803b1473b3c659d57a23b5fa491ad83c6d40f2af58e4dbb", - "sha256:48b389b1fd5144603d61d752afd7167dfd205973a43151ae5045b35793232aa2", - "sha256:4e67d26532bfd8b7f7c05d5a766d6f437b362c1bf203a3a5ce3593a645e870b8", - "sha256:516a405f174fd3b88829eabfe4bb296ac602d6a0f68e0d64d5ac9456194a5b7e", - "sha256:5ba5c243f4004c750836f81606a9fcb7841f8874ad8f3bf204ff5e56332b72b9", - "sha256:5bdc0f1f610d067c70aa3737ed06e2726fd9d6f7bfee4a351f4c40b6831f4e82", - "sha256:6107e445faf057c118d5050560695e46d272e5301feffda3c41849641222a828", - "sha256:6327b572f5770293fc062a7ec04160e89741e8552bf1c358d1a23eba68166759", - "sha256:669b29a9eca6146465cc574659058ed949748f0809a2582d1f1a324eb91054dc", - "sha256:6ce01337d23884b21c03869d2f68c5523d43174d4fc405490eb0091057943118", - "sha256:6d872186c1617d143969defeadac5a904e6e374183e07977eedef9c07c8953bf", - "sha256:6f76a90c345796c01d85e6332e81cab6d70de83b829cf1d9762d0a3da59c7932", - "sha256:70d2aa9fb00cf52034feac4b913181a6e10356019b18ef89bc7c12a283bf5f5a", - "sha256:7cbc78dc018596315d4e7841c8c3a7ae31cc4d638c9b627f87d52e8abaaf2d29", - "sha256:856bf0924d24e7f93b8aee12a3a1095c34085600aa805693fb7f5d1962393206", - "sha256:8a98748ed1a1df4ee1d6f927e151ed6c1a09d5ec21684de879c7ea6aa96f58f2", - "sha256:93a7350f6706b31f457c1457d3a3259ff9071a66f312ae64dc024f049055f72c", - "sha256:964823b2fc77b55355999ade496c54dde161c621cb1f6eac61dc30ed1b63cd4c", - "sha256:a003ac9edc22d99ae1286b0875c460351f4e101f8c9d9d2576e78d7e048f64e0", - "sha256:a0ce71725cacc9ebf839630772b07eeec220cbb5f03be1399e0457a1464f8e1a", - "sha256:a47eef975d2b8b721775a0fa286f50eab535b9d56c70a6e62842134cf7841195", - "sha256:a8b5b9712783415695663bd463990e2f00c6750562e6ad1d28e072a611c5f2a6", - "sha256:a9015f5b8af1bb6837a3fcb0cdf3b874fe3385ff6274e8b7925d81ccaec3c5c9", - "sha256:aec510255ce690d240f7cb23d7114f6b351c733a74c279a84def763660a2c3bc", - "sha256:b00e7bcd71caa0282cbe3c90966f738e2db91e64092a877c3ff7f19a1628fdcb", - "sha256:b50aaac7d05c2c26dfd50c3321199f019ba76bb650e346a6ef3616306eed67b0", - "sha256:b7b6ea9e36d32582cda3465f54c4b454f62f23cb083ebc7a94e2ca6ef011c3a7", - "sha256:bb9333f58fc3a2296fb1d54576138d4cf5d496a2cc118422bd77835e6ae0b9cb", - "sha256:c1c13185b90bbd3f8b5963cd8ce7ad4ff441924c31e23c975cb150e27c2bf67a", - "sha256:c3b8bd3133cd50f6b637bb4322822c94c5ce4bf0d724ed5ae70afce62187c492", - "sha256:c5d97162c196ce54af6700949ddf9409e9833ef1003b4741c2b39ef46f1d9720", - "sha256:c815270206f983309915a6844fe994b2fa47e5d05c4c4cef267c3b30e34dbe42", - "sha256:cab2eba3830bf4f6d91e2d6718e0e1c14a2f5ad1af68a89d24ace0c6b17cced7", - "sha256:d1df34588123fcc88c872f5acb6f74ae59e9d182a2707097f9e28275ec26a12d", - "sha256:d6bdcd415ba87846fd317bee0774e412e8792832e7805938987e4ede1d13046d", - "sha256:db9a30ec064129d605d0f1aedc93e00894b9334ec74ba9c6bdd08147434b33eb", - "sha256:dbc183e7bef690c9abe5ea67b7b60fdbca81aa8da43468287dae7b5c046107d4", - "sha256:dca802c8db0720ce1c49cce1149ff7b06e91ba15fa84b1d59144fef1a1bc7ac2", - "sha256:dec6b307ce928e8e112a6bb9921a1cb00a0e14979bf28b98e084a4b8a742bd9b", - "sha256:df8bb0010fdd0a743b7542589223a2816bdde4d94bb5ad67884348fa2c1c67e8", - "sha256:e4094c7b464cf0a858e75cd14b03509e84789abf7b79f8537e6a72152109c76e", - "sha256:e4760a68cab57bfaa628938e9c2971137e05ce48e762a9cb53b76c9b569f1204", - "sha256:eb09b82377233b902d4c3fbeeb7ad731cdab579c6c6fda1f763cd779139e47c3", - "sha256:eb862356ee9391dc5a0b3cbc00f416b48c1b9a52d252d898e5b7696a5f9fe150", - "sha256:ef9528915df81b8f4c7612b19b8628214c65c9b7f74db2e34a646a0a2a0da2d4", - "sha256:f3157624b7558b914cb039fd1af735e5e8049a87c817cc215109ad1c8779df76", - "sha256:f3e0992f23bbb0be00a921eae5363329253c3b86287db27092461c887b791e5e", - "sha256:f9338cc05451f1942d0d8203ec2c346c830f8e86469903d5126c1f0a13a2bcbb", - "sha256:ffef8fd58a36fb5f1196919638f73dd3ae0db1a878982b27a9a5a176ede4ba91" + "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8", + "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2", + "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1", + "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15", + "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36", + "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", + "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8", + "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36", + "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17", + "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf", + "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc", + "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3", + "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed", + "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702", + "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1", + "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8", + "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903", + "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6", + "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d", + "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b", + "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e", + "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be", + "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c", + "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683", + "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9", + "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c", + "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8", + "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1", + "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4", + "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655", + "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67", + "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595", + "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0", + "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65", + "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41", + "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6", + "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401", + "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6", + "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3", + "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16", + "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93", + "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e", + "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4", + "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964", + "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c", + "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576", + "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0", + "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3", + "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662", + "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3", + "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff", + "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5", + "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd", + "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f", + "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5", + "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14", + "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d", + "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9", + "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7", + "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382", + "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a", + "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e", + "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a", + "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4", + "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99", + "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87", + "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b" ], "markers": "platform_python_implementation != 'PyPy'", - "version": "==1.17.0" + "version": "==1.17.1" }, "charset-normalizer": { "hashes": [ - "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027", - "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087", - "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786", - "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8", - "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09", - "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185", - "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574", - "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e", - "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519", - "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898", - "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269", - "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3", - "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f", - "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6", - "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8", - "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a", - "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73", - "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc", - "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714", - "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2", - "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc", - "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce", - "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d", - "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e", - "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6", - "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269", - "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96", - "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d", - "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a", - "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4", - "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77", - "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d", - "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0", - "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed", - "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068", - "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac", - "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25", - "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8", - "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab", - "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26", - "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2", - "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db", - "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f", - "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5", - "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99", - "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c", - "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d", - "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811", - "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa", - "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a", - "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03", - "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b", - "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04", - "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c", - "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001", - "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458", - "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389", - "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99", - "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985", - "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537", - "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238", - "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f", - "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d", - "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796", - "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a", - "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143", - "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8", - "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c", - "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5", - "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5", - "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711", - "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4", - "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6", - "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c", - "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7", - "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4", - "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b", - "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae", - "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12", - "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c", - "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae", - "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8", - "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887", - "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b", - "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4", - "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f", - "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5", - "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33", - "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519", - "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561" + "sha256:0099d79bdfcf5c1f0c2c72f91516702ebf8b0b8ddd8905f97a8aecf49712c621", + "sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6", + "sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8", + "sha256:0b309d1747110feb25d7ed6b01afdec269c647d382c857ef4663bbe6ad95a912", + "sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c", + "sha256:0de7b687289d3c1b3e8660d0741874abe7888100efe14bd0f9fd7141bcbda92b", + "sha256:1110e22af8ca26b90bd6364fe4c763329b0ebf1ee213ba32b68c73de5752323d", + "sha256:130272c698667a982a5d0e626851ceff662565379baf0ff2cc58067b81d4f11d", + "sha256:136815f06a3ae311fae551c3df1f998a1ebd01ddd424aa5603a4336997629e95", + "sha256:14215b71a762336254351b00ec720a8e85cada43b987da5a042e4ce3e82bd68e", + "sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565", + "sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64", + "sha256:2006769bd1640bdf4d5641c69a3d63b71b81445473cac5ded39740a226fa88ab", + "sha256:20587d20f557fe189b7947d8e7ec5afa110ccf72a3128d61a2a387c3313f46be", + "sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e", + "sha256:27623ba66c183eca01bf9ff833875b459cad267aeeb044477fedac35e19ba907", + "sha256:285e96d9d53422efc0d7a17c60e59f37fbf3dfa942073f666db4ac71e8d726d0", + "sha256:2de62e8801ddfff069cd5c504ce3bc9672b23266597d4e4f50eda28846c322f2", + "sha256:2f6c34da58ea9c1a9515621f4d9ac379871a8f21168ba1b5e09d74250de5ad62", + "sha256:309a7de0a0ff3040acaebb35ec45d18db4b28232f21998851cfa709eeff49d62", + "sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23", + "sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc", + "sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284", + "sha256:40d3ff7fc90b98c637bda91c89d51264a3dcf210cade3a2c6f838c7268d7a4ca", + "sha256:425c5f215d0eecee9a56cdb703203dda90423247421bf0d67125add85d0c4455", + "sha256:43193c5cda5d612f247172016c4bb71251c784d7a4d9314677186a838ad34858", + "sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b", + "sha256:47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594", + "sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc", + "sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db", + "sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b", + "sha256:4ec9dd88a5b71abfc74e9df5ebe7921c35cbb3b641181a531ca65cdb5e8e4dea", + "sha256:4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6", + "sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920", + "sha256:55f56e2ebd4e3bc50442fbc0888c9d8c94e4e06a933804e2af3e89e2f9c1c749", + "sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7", + "sha256:5d447056e2ca60382d460a604b6302d8db69476fd2015c81e7c35417cfabe4cd", + "sha256:5ed2e36c3e9b4f21dd9422f6893dec0abf2cca553af509b10cd630f878d3eb99", + "sha256:5ff2ed8194587faf56555927b3aa10e6fb69d931e33953943bc4f837dfee2242", + "sha256:62f60aebecfc7f4b82e3f639a7d1433a20ec32824db2199a11ad4f5e146ef5ee", + "sha256:63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129", + "sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2", + "sha256:6b493a043635eb376e50eedf7818f2f322eabbaa974e948bd8bdd29eb7ef2a51", + "sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee", + "sha256:6fd30dc99682dc2c603c2b315bded2799019cea829f8bf57dc6b61efde6611c8", + "sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b", + "sha256:7706f5850360ac01d80c89bcef1640683cc12ed87f42579dab6c5d3ed6888613", + "sha256:7782afc9b6b42200f7362858f9e73b1f8316afb276d316336c0ec3bd73312742", + "sha256:79983512b108e4a164b9c8d34de3992f76d48cadc9554c9e60b43f308988aabe", + "sha256:7f683ddc7eedd742e2889d2bfb96d69573fde1d92fcb811979cdb7165bb9c7d3", + "sha256:82357d85de703176b5587dbe6ade8ff67f9f69a41c0733cf2425378b49954de5", + "sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631", + "sha256:86f4e8cca779080f66ff4f191a685ced73d2f72d50216f7112185dc02b90b9b7", + "sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15", + "sha256:8ce7fd6767a1cc5a92a639b391891bf1c268b03ec7e021c7d6d902285259685c", + "sha256:8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea", + "sha256:9289fd5dddcf57bab41d044f1756550f9e7cf0c8e373b8cdf0ce8773dc4bd417", + "sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250", + "sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88", + "sha256:95c3c157765b031331dd4db3c775e58deaee050a3042fcad72cbc4189d7c8dca", + "sha256:980b4f289d1d90ca5efcf07958d3eb38ed9c0b7676bf2831a54d4f66f9c27dfa", + "sha256:9ae4ef0b3f6b41bad6366fb0ea4fc1d7ed051528e113a60fa2a65a9abb5b1d99", + "sha256:9c98230f5042f4945f957d006edccc2af1e03ed5e37ce7c373f00a5a4daa6149", + "sha256:9fa2566ca27d67c86569e8c85297aaf413ffab85a8960500f12ea34ff98e4c41", + "sha256:a14969b8691f7998e74663b77b4c36c0337cb1df552da83d5c9004a93afdb574", + "sha256:a8aacce6e2e1edcb6ac625fb0f8c3a9570ccc7bfba1f63419b3769ccf6a00ed0", + "sha256:a8e538f46104c815be19c975572d74afb53f29650ea2025bbfaef359d2de2f7f", + "sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d", + "sha256:aa693779a8b50cd97570e5a0f343538a8dbd3e496fa5dcb87e29406ad0299654", + "sha256:ab22fbd9765e6954bc0bcff24c25ff71dcbfdb185fcdaca49e81bac68fe724d3", + "sha256:ab2e5bef076f5a235c3774b4f4028a680432cded7cad37bba0fd90d64b187d19", + "sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90", + "sha256:af73657b7a68211996527dbfeffbb0864e043d270580c5aef06dc4b659a4b578", + "sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9", + "sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1", + "sha256:b8831399554b92b72af5932cdbbd4ddc55c55f631bb13ff8fe4e6536a06c5c51", + "sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719", + "sha256:bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236", + "sha256:bd7af3717683bea4c87acd8c0d3d5b44d56120b26fd3f8a692bdd2d5260c620a", + "sha256:bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c", + "sha256:c3e446d253bd88f6377260d07c895816ebf33ffffd56c1c792b13bff9c3e1ade", + "sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944", + "sha256:c94057af19bc953643a33581844649a7fdab902624d2eb739738a30e2b3e60fc", + "sha256:cab5d0b79d987c67f3b9e9c53f54a61360422a5a0bc075f43cab5621d530c3b6", + "sha256:ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6", + "sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27", + "sha256:d5b054862739d276e09928de37c79ddeec42a6e1bfc55863be96a36ba22926f6", + "sha256:dbe03226baf438ac4fda9e2d0715022fd579cb641c4cf639fa40d53b2fe6f3e2", + "sha256:dc15e99b2d8a656f8e666854404f1ba54765871104e50c8e9813af8a7db07f12", + "sha256:dcaf7c1524c0542ee2fc82cc8ec337f7a9f7edee2532421ab200d2b920fc97cf", + "sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114", + "sha256:dd9a8bd8900e65504a305bf8ae6fa9fbc66de94178c420791d0293702fce2df7", + "sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf", + "sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d", + "sha256:e91f541a85298cf35433bf66f3fab2a4a2cff05c127eeca4af174f6d497f0d4b", + "sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed", + "sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03", + "sha256:f09cb5a7bbe1ecae6e87901a2eb23e0256bb524a79ccc53eb0b7629fbe7677c4", + "sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67", + "sha256:f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365", + "sha256:f28f891ccd15c514a0981f3b9db9aa23d62fe1a99997512b0491d2ed323d229a", + "sha256:f3e73a4255342d4eb26ef6df01e3962e73aa29baa3124a8e824c5d3364a65748", + "sha256:f606a1881d2663630ea5b8ce2efe2111740df4b687bd78b34a8131baa007f79b", + "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079", + "sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482" ], "markers": "python_full_version >= '3.7.0'", - "version": "==3.3.2" + "version": "==3.4.0" }, "click": { "hashes": [ @@ -406,120 +405,45 @@ "markers": "python_version >= '3.7'", "version": "==8.1.7" }, - "contourpy": { - "hashes": [ - "sha256:00e5388f71c1a0610e6fe56b5c44ab7ba14165cdd6d695429c5cd94021e390b2", - "sha256:10a37ae557aabf2509c79715cd20b62e4c7c28b8cd62dd7d99e5ed3ce28c3fd9", - "sha256:11959f0ce4a6f7b76ec578576a0b61a28bdc0696194b6347ba3f1c53827178b9", - "sha256:187fa1d4c6acc06adb0fae5544c59898ad781409e61a926ac7e84b8f276dcef4", - "sha256:1a07fc092a4088ee952ddae19a2b2a85757b923217b7eed584fdf25f53a6e7ce", - "sha256:1cac0a8f71a041aa587410424ad46dfa6a11f6149ceb219ce7dd48f6b02b87a7", - "sha256:1d59e739ab0e3520e62a26c60707cc3ab0365d2f8fecea74bfe4de72dc56388f", - "sha256:2855c8b0b55958265e8b5888d6a615ba02883b225f2227461aa9127c578a4922", - "sha256:2e785e0f2ef0d567099b9ff92cbfb958d71c2d5b9259981cd9bee81bd194c9a4", - "sha256:309be79c0a354afff9ff7da4aaed7c3257e77edf6c1b448a779329431ee79d7e", - "sha256:39f3ecaf76cd98e802f094e0d4fbc6dc9c45a8d0c4d185f0f6c2234e14e5f75b", - "sha256:457499c79fa84593f22454bbd27670227874cd2ff5d6c84e60575c8b50a69619", - "sha256:49e70d111fee47284d9dd867c9bb9a7058a3c617274900780c43e38d90fe1205", - "sha256:4c75507d0a55378240f781599c30e7776674dbaf883a46d1c90f37e563453480", - "sha256:4c863140fafc615c14a4bf4efd0f4425c02230eb8ef02784c9a156461e62c965", - "sha256:4d8908b3bee1c889e547867ca4cdc54e5ab6be6d3e078556814a22457f49423c", - "sha256:5b9eb0ca724a241683c9685a484da9d35c872fd42756574a7cfbf58af26677fd", - "sha256:6022cecf8f44e36af10bd9118ca71f371078b4c168b6e0fab43d4a889985dbb5", - "sha256:6150ffa5c767bc6332df27157d95442c379b7dce3a38dff89c0f39b63275696f", - "sha256:62828cada4a2b850dbef89c81f5a33741898b305db244904de418cc957ff05dc", - "sha256:7b4182299f251060996af5249c286bae9361fa8c6a9cda5efc29fe8bfd6062ec", - "sha256:94b34f32646ca0414237168d68a9157cb3889f06b096612afdd296003fdd32fd", - "sha256:9ce6889abac9a42afd07a562c2d6d4b2b7134f83f18571d859b25624a331c90b", - "sha256:9cffe0f850e89d7c0012a1fb8730f75edd4320a0a731ed0c183904fe6ecfc3a9", - "sha256:a12a813949e5066148712a0626895c26b2578874e4cc63160bb007e6df3436fe", - "sha256:a1eea9aecf761c661d096d39ed9026574de8adb2ae1c5bd7b33558af884fb2ce", - "sha256:a31f94983fecbac95e58388210427d68cd30fe8a36927980fab9c20062645609", - "sha256:ac58bdee53cbeba2ecad824fa8159493f0bf3b8ea4e93feb06c9a465d6c87da8", - "sha256:af3f4485884750dddd9c25cb7e3915d83c2db92488b38ccb77dd594eac84c4a0", - "sha256:b33d2bc4f69caedcd0a275329eb2198f560b325605810895627be5d4b876bf7f", - "sha256:b59c0ffceff8d4d3996a45f2bb6f4c207f94684a96bf3d9728dbb77428dd8cb8", - "sha256:bb6834cbd983b19f06908b45bfc2dad6ac9479ae04abe923a275b5f48f1a186b", - "sha256:bd3db01f59fdcbce5b22afad19e390260d6d0222f35a1023d9adc5690a889364", - "sha256:bd7c23df857d488f418439686d3b10ae2fbf9bc256cd045b37a8c16575ea1040", - "sha256:c2528d60e398c7c4c799d56f907664673a807635b857df18f7ae64d3e6ce2d9f", - "sha256:d31a63bc6e6d87f77d71e1abbd7387ab817a66733734883d1fc0021ed9bfa083", - "sha256:d4492d82b3bc7fbb7e3610747b159869468079fe149ec5c4d771fa1f614a14df", - "sha256:ddcb8581510311e13421b1f544403c16e901c4e8f09083c881fab2be80ee31ba", - "sha256:e1d59258c3c67c865435d8fbeb35f8c59b8bef3d6f46c1f29f6123556af28445", - "sha256:eb3315a8a236ee19b6df481fc5f997436e8ade24a9f03dfdc6bd490fea20c6da", - "sha256:ef2b055471c0eb466033760a521efb9d8a32b99ab907fc8358481a1dd29e3bd3", - "sha256:ef5adb9a3b1d0c645ff694f9bca7702ec2c70f4d734f9922ea34de02294fdf72", - "sha256:f32c38afb74bd98ce26de7cc74a67b40afb7b05aae7b42924ea990d51e4dac02", - "sha256:fe0ccca550bb8e5abc22f530ec0466136379c01321fd94f30a22231e8a48d985" - ], - "markers": "python_version >= '3.9'", - "version": "==1.2.1" - }, "cryptography": { "hashes": [ - "sha256:0663585d02f76929792470451a5ba64424acc3cd5227b03921dab0e2f27b1709", - "sha256:08a24a7070b2b6804c1940ff0f910ff728932a9d0e80e7814234269f9d46d069", - "sha256:232ce02943a579095a339ac4b390fbbe97f5b5d5d107f8a08260ea2768be8cc2", - "sha256:2905ccf93a8a2a416f3ec01b1a7911c3fe4073ef35640e7ee5296754e30b762b", - "sha256:299d3da8e00b7e2b54bb02ef58d73cd5f55fb31f33ebbf33bd00d9aa6807df7e", - "sha256:2c6d112bf61c5ef44042c253e4859b3cbbb50df2f78fa8fae6747a7814484a70", - "sha256:31e44a986ceccec3d0498e16f3d27b2ee5fdf69ce2ab89b52eaad1d2f33d8778", - "sha256:3d9a1eca329405219b605fac09ecfc09ac09e595d6def650a437523fcd08dd22", - "sha256:3dcdedae5c7710b9f97ac6bba7e1052b95c7083c9d0e9df96e02a1932e777895", - "sha256:47ca71115e545954e6c1d207dd13461ab81f4eccfcb1345eac874828b5e3eaaf", - "sha256:4a997df8c1c2aae1e1e5ac49c2e4f610ad037fc5a3aadc7b64e39dea42249431", - "sha256:51956cf8730665e2bdf8ddb8da0056f699c1a5715648c1b0144670c1ba00b48f", - "sha256:5bcb8a5620008a8034d39bce21dc3e23735dfdb6a33a06974739bfa04f853947", - "sha256:64c3f16e2a4fc51c0d06af28441881f98c5d91009b8caaff40cf3548089e9c74", - "sha256:6e2b11c55d260d03a8cf29ac9b5e0608d35f08077d8c087be96287f43af3ccdc", - "sha256:7b3f5fe74a5ca32d4d0f302ffe6680fcc5c28f8ef0dc0ae8f40c0f3a1b4fca66", - "sha256:844b6d608374e7d08f4f6e6f9f7b951f9256db41421917dfb2d003dde4cd6b66", - "sha256:9a8d6802e0825767476f62aafed40532bd435e8a5f7d23bd8b4f5fd04cc80ecf", - "sha256:aae4d918f6b180a8ab8bf6511a419473d107df4dbb4225c7b48c5c9602c38c7f", - "sha256:ac1955ce000cb29ab40def14fd1bbfa7af2017cca696ee696925615cafd0dce5", - "sha256:b88075ada2d51aa9f18283532c9f60e72170041bba88d7f37e49cbb10275299e", - "sha256:cb013933d4c127349b3948aa8aaf2f12c0353ad0eccd715ca789c8a0f671646f", - "sha256:cc70b4b581f28d0a254d006f26949245e3657d40d8857066c2ae22a61222ef55", - "sha256:e9c5266c432a1e23738d178e51c2c7a5e2ddf790f248be939448c0ba2021f9d1", - "sha256:ea9e57f8ea880eeea38ab5abf9fbe39f923544d7884228ec67d666abd60f5a47", - "sha256:ee0c405832ade84d4de74b9029bedb7b31200600fa524d218fc29bfa371e97f5", - "sha256:fdcb265de28585de5b859ae13e3846a8e805268a823a12a4da2597f1f5afc9f0" + "sha256:014f58110f53237ace6a408b5beb6c427b64e084eb451ef25a28308270086494", + "sha256:1bbcce1a551e262dfbafb6e6252f1ae36a248e615ca44ba302df077a846a8806", + "sha256:203e92a75716d8cfb491dc47c79e17d0d9207ccffcbcb35f598fbe463ae3444d", + "sha256:27e613d7077ac613e399270253259d9d53872aaf657471473ebfc9a52935c062", + "sha256:2bd51274dcd59f09dd952afb696bf9c61a7a49dfc764c04dd33ef7a6b502a1e2", + "sha256:38926c50cff6f533f8a2dae3d7f19541432610d114a70808f0926d5aaa7121e4", + "sha256:511f4273808ab590912a93ddb4e3914dfd8a388fed883361b02dea3791f292e1", + "sha256:58d4e9129985185a06d849aa6df265bdd5a74ca6e1b736a77959b498e0505b85", + "sha256:5b43d1ea6b378b54a1dc99dd8a2b5be47658fe9a7ce0a58ff0b55f4b43ef2b84", + "sha256:61ec41068b7b74268fa86e3e9e12b9f0c21fcf65434571dbb13d954bceb08042", + "sha256:666ae11966643886c2987b3b721899d250855718d6d9ce41b521252a17985f4d", + "sha256:68aaecc4178e90719e95298515979814bda0cbada1256a4485414860bd7ab962", + "sha256:7c05650fe8023c5ed0d46793d4b7d7e6cd9c04e68eabe5b0aeea836e37bdcec2", + "sha256:80eda8b3e173f0f247f711eef62be51b599b5d425c429b5d4ca6a05e9e856baa", + "sha256:8385d98f6a3bf8bb2d65a73e17ed87a3ba84f6991c155691c51112075f9ffc5d", + "sha256:88cce104c36870d70c49c7c8fd22885875d950d9ee6ab54df2745f83ba0dc365", + "sha256:9d3cdb25fa98afdd3d0892d132b8d7139e2c087da1712041f6b762e4f807cc96", + "sha256:a575913fb06e05e6b4b814d7f7468c2c660e8bb16d8d5a1faf9b33ccc569dd47", + "sha256:ac119bb76b9faa00f48128b7f5679e1d8d437365c5d26f1c2c3f0da4ce1b553d", + "sha256:c1332724be35d23a854994ff0b66530119500b6053d0bd3363265f7e5e77288d", + "sha256:d03a475165f3134f773d1388aeb19c2d25ba88b6a9733c5c590b9ff7bbfa2e0c", + "sha256:d75601ad10b059ec832e78823b348bfa1a59f6b8d545db3a24fd44362a1564cb", + "sha256:de41fd81a41e53267cb020bb3a7212861da53a7d39f863585d13ea11049cf277", + "sha256:e710bf40870f4db63c3d7d929aa9e09e4e7ee219e703f949ec4073b4294f6172", + "sha256:ea25acb556320250756e53f9e20a4177515f012c9eaea17eb7587a8c4d8ae034", + "sha256:f98bf604c82c416bc829e490c700ca1553eafdf2912a91e23a79d97d9801372a", + "sha256:fba1007b3ef89946dbbb515aeeb41e30203b004f0b4b00e5e16078b518563289" ], "markers": "python_version >= '3.7'", - "version": "==43.0.0" - }, - "cycler": { - "hashes": [ - "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30", - "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c" - ], - "markers": "python_version >= '3.8'", - "version": "==0.12.1" - }, - "datasets": { - "hashes": [ - "sha256:25e4e097110ce28824b746a107727ada94024cba11db8bc588d468414692b65a", - "sha256:998f85a8460f1bd982e5bd058f8a0808eef424249e3df1e8cdd594ccd0dc8ba2" - ], - "markers": "python_full_version >= '3.8.0'", - "version": "==2.21.0" + "version": "==43.0.1" }, "dbrepo": { "hashes": [ - "sha256:0a04b67204de6dc969ec68fb21aaead898156077e8a5b6f1e03bb5ab0e124a61", - "sha256:454a182b772cb777d27a22bb334bf059ce68d4e6b5fecae802678fabfdf3f934" + "sha256:84607677b0826bb9b2fa120aacdf56d16c8d9ae423f435b2bd2c22b1c965a33c" ], "markers": "python_version >= '3.11'", - "path": "./lib/dbrepo-1.4.5.tar.gz" - }, - "dill": { - "hashes": [ - "sha256:3ebe3c479ad625c4553aca177444d89b486b1d84982eeacded644afc0cf797ca", - "sha256:c36ca9ffb54365bdd2f8eb3eff7d2a21237f8452b57ace88b1ac615b7e815bd7" - ], - "markers": "python_version >= '3.8'", - "version": "==0.3.8" + "path": "./lib/dbrepo-1.4.7.tar.gz" }, "events": { "hashes": [ @@ -536,21 +460,6 @@ "markers": "python_version >= '3.7'", "version": "==1.2.2" }, - "filelock": { - "hashes": [ - "sha256:2207938cbc1844345cb01a5a95524dae30f0ce089eba5b00378295a17e3e90cb", - "sha256:6ca1fffae96225dab4c6eaf1c4f4f28cd2568d3ec2a44e15a08520504de468e7" - ], - "markers": "python_version >= '3.8'", - "version": "==3.15.4" - }, - "flagembedding": { - "hashes": [ - "sha256:12c55eb535e9325c3efa539af4aa39c6f4e4e1b6441db7778d42ad0612906501" - ], - "index": "pypi", - "version": "==1.2.11" - }, "flasgger": { "hashes": [ "sha256:ca098e10bfbb12f047acc6299cc70a33851943a746e550d86e65e60d4df245fb" @@ -567,22 +476,13 @@ "markers": "python_version >= '3.8'", "version": "==3.0.3" }, - "flask-caching": { - "hashes": [ - "sha256:51771c75682e5abc1483b78b96d9131d7941dc669b073852edfa319dd4e29b6e", - "sha256:d7e4ca64a33b49feb339fcdd17e6ba25f5e01168cf885e53790e885f83a4d2cf" - ], - "index": "pypi", - "markers": "python_version >= '3.8'", - "version": "==2.3.0" - }, "flask-cors": { "hashes": [ - "sha256:eeb69b342142fdbf4766ad99357a7f3876a2ceb77689dc10ff912aac06c389e4", - "sha256:f2a704e4458665580c074b714c4627dd5a306b333deb9074d0b1794dfa2fb677" + "sha256:5aadb4b950c4e93745034594d9f3ea6591f734bb3662e16e255ffbf5e89c88ef", + "sha256:b9e307d082a9261c100d8fb0ba909eec6a228ed1b60a8315fd85f783d61910bc" ], "index": "pypi", - "version": "==4.0.1" + "version": "==5.0.0" }, "flask-httpauth": { "hashes": [ @@ -601,54 +501,6 @@ "markers": "python_version >= '3.7' and python_version < '4'", "version": "==4.6.0" }, - "fonttools": { - "hashes": [ - "sha256:02569e9a810f9d11f4ae82c391ebc6fb5730d95a0657d24d754ed7763fb2d122", - "sha256:0679a30b59d74b6242909945429dbddb08496935b82f91ea9bf6ad240ec23397", - "sha256:10f5e6c3510b79ea27bb1ebfcc67048cde9ec67afa87c7dd7efa5c700491ac7f", - "sha256:2af40ae9cdcb204fc1d8f26b190aa16534fcd4f0df756268df674a270eab575d", - "sha256:32f029c095ad66c425b0ee85553d0dc326d45d7059dbc227330fc29b43e8ba60", - "sha256:35250099b0cfb32d799fb5d6c651220a642fe2e3c7d2560490e6f1d3f9ae9169", - "sha256:3b3c8ebafbee8d9002bd8f1195d09ed2bd9ff134ddec37ee8f6a6375e6a4f0e8", - "sha256:4824c198f714ab5559c5be10fd1adf876712aa7989882a4ec887bf1ef3e00e31", - "sha256:5ff7e5e9bad94e3a70c5cd2fa27f20b9bb9385e10cddab567b85ce5d306ea923", - "sha256:651390c3b26b0c7d1f4407cad281ee7a5a85a31a110cbac5269de72a51551ba2", - "sha256:6e08f572625a1ee682115223eabebc4c6a2035a6917eac6f60350aba297ccadb", - "sha256:6ed170b5e17da0264b9f6fae86073be3db15fa1bd74061c8331022bca6d09bab", - "sha256:73379d3ffdeecb376640cd8ed03e9d2d0e568c9d1a4e9b16504a834ebadc2dfb", - "sha256:75a157d8d26c06e64ace9df037ee93a4938a4606a38cb7ffaf6635e60e253b7a", - "sha256:791b31ebbc05197d7aa096bbc7bd76d591f05905d2fd908bf103af4488e60670", - "sha256:7b6b35e52ddc8fb0db562133894e6ef5b4e54e1283dff606fda3eed938c36fc8", - "sha256:84ec3fb43befb54be490147b4a922b5314e16372a643004f182babee9f9c3407", - "sha256:8959a59de5af6d2bec27489e98ef25a397cfa1774b375d5787509c06659b3671", - "sha256:9dfdae43b7996af46ff9da520998a32b105c7f098aeea06b2226b30e74fbba88", - "sha256:9e6ceba2a01b448e36754983d376064730690401da1dd104ddb543519470a15f", - "sha256:9efd176f874cb6402e607e4cc9b4a9cd584d82fc34a4b0c811970b32ba62501f", - "sha256:a1c7c5aa18dd3b17995898b4a9b5929d69ef6ae2af5b96d585ff4005033d82f0", - "sha256:aae7bd54187e8bf7fd69f8ab87b2885253d3575163ad4d669a262fe97f0136cb", - "sha256:b21952c092ffd827504de7e66b62aba26fdb5f9d1e435c52477e6486e9d128b2", - "sha256:b96cd370a61f4d083c9c0053bf634279b094308d52fdc2dd9a22d8372fdd590d", - "sha256:becc5d7cb89c7b7afa8321b6bb3dbee0eec2b57855c90b3e9bf5fb816671fa7c", - "sha256:bee32ea8765e859670c4447b0817514ca79054463b6b79784b08a8df3a4d78e3", - "sha256:c6e7170d675d12eac12ad1a981d90f118c06cf680b42a2d74c6c931e54b50719", - "sha256:c818c058404eb2bba05e728d38049438afd649e3c409796723dfc17cd3f08749", - "sha256:c8696544c964500aa9439efb6761947393b70b17ef4e82d73277413f291260a4", - "sha256:c9cd19cf4fe0595ebdd1d4915882b9440c3a6d30b008f3cc7587c1da7b95be5f", - "sha256:d4d0096cb1ac7a77b3b41cd78c9b6bc4a400550e21dc7a92f2b5ab53ed74eb02", - "sha256:d92d3c2a1b39631a6131c2fa25b5406855f97969b068e7e08413325bc0afba58", - "sha256:da33440b1413bad53a8674393c5d29ce64d8c1a15ef8a77c642ffd900d07bfe1", - "sha256:e013aae589c1c12505da64a7d8d023e584987e51e62006e1bb30d72f26522c41", - "sha256:e128778a8e9bc11159ce5447f76766cefbd876f44bd79aff030287254e4752c4", - "sha256:e54f1bba2f655924c1138bbc7fa91abd61f45c68bd65ab5ed985942712864bbb", - "sha256:e5b708073ea3d684235648786f5f6153a48dc8762cdfe5563c57e80787c29fbb", - "sha256:e8bf06b94694251861ba7fdeea15c8ec0967f84c3d4143ae9daf42bbc7717fe3", - "sha256:f08df60fbd8d289152079a65da4e66a447efc1d5d5a4d3f299cdd39e3b2e4a7d", - "sha256:f1f8758a2ad110bd6432203a344269f445a2907dc24ef6bccfd0ac4e14e0d71d", - "sha256:f677ce218976496a587ab17140da141557beb91d2a5c1a14212c994093f2eae2" - ], - "markers": "python_version >= '3.8'", - "version": "==4.53.1" - }, "frozenlist": { "hashes": [ "sha256:04ced3e6a46b4cfffe20f9ae482818e34eba9b5fb0ce4056e4cc9b6e212d09b7", @@ -732,129 +584,130 @@ "markers": "python_version >= '3.8'", "version": "==1.4.1" }, - "fsspec": { - "extras": [ - "http" - ], - "hashes": [ - "sha256:3cb443f8bcd2efb31295a5b9fdb02aee81d8452c80d28f97a6d0959e6cee101e", - "sha256:fad7d7e209dd4c1208e3bbfda706620e0da5142bebbd9c384afb95b07e798e49" - ], - "markers": "python_version >= '3.8'", - "version": "==2024.6.1" - }, "gevent": { "hashes": [ - "sha256:03aa5879acd6b7076f6a2a307410fb1e0d288b84b03cdfd8c74db8b4bc882fc5", - "sha256:117e5837bc74a1673605fb53f8bfe22feb6e5afa411f524c835b2ddf768db0de", - "sha256:141a2b24ad14f7b9576965c0c84927fc85f824a9bb19f6ec1e61e845d87c9cd8", - "sha256:14532a67f7cb29fb055a0e9b39f16b88ed22c66b96641df8c04bdc38c26b9ea5", - "sha256:1dffb395e500613e0452b9503153f8f7ba587c67dd4a85fc7cd7aa7430cb02cc", - "sha256:2955eea9c44c842c626feebf4459c42ce168685aa99594e049d03bedf53c2800", - "sha256:2ae3a25ecce0a5b0cd0808ab716bfca180230112bb4bc89b46ae0061d62d4afe", - "sha256:2e9ac06f225b696cdedbb22f9e805e2dd87bf82e8fa5e17756f94e88a9d37cf7", - "sha256:368a277bd9278ddb0fde308e6a43f544222d76ed0c4166e0d9f6b036586819d9", - "sha256:3adfb96637f44010be8abd1b5e73b5070f851b817a0b182e601202f20fa06533", - "sha256:3d5325ccfadfd3dcf72ff88a92fb8fc0b56cacc7225f0f4b6dcf186c1a6eeabc", - "sha256:432fc76f680acf7cf188c2ee0f5d3ab73b63c1f03114c7cd8a34cebbe5aa2056", - "sha256:44098038d5e2749b0784aabb27f1fcbb3f43edebedf64d0af0d26955611be8d6", - "sha256:5a1df555431f5cd5cc189a6ee3544d24f8c52f2529134685f1e878c4972ab026", - "sha256:6c47ae7d1174617b3509f5d884935e788f325eb8f1a7efc95d295c68d83cce40", - "sha256:6f947a9abc1a129858391b3d9334c45041c08a0f23d14333d5b844b6e5c17a07", - "sha256:782a771424fe74bc7e75c228a1da671578c2ba4ddb2ca09b8f959abdf787331e", - "sha256:7899a38d0ae7e817e99adb217f586d0a4620e315e4de577444ebeeed2c5729be", - "sha256:7b00f8c9065de3ad226f7979154a7b27f3b9151c8055c162332369262fc025d8", - "sha256:8f4b8e777d39013595a7740b4463e61b1cfe5f462f1b609b28fbc1e4c4ff01e5", - "sha256:90cbac1ec05b305a1b90ede61ef73126afdeb5a804ae04480d6da12c56378df1", - "sha256:918cdf8751b24986f915d743225ad6b702f83e1106e08a63b736e3a4c6ead789", - "sha256:9202f22ef811053077d01f43cc02b4aaf4472792f9fd0f5081b0b05c926cca19", - "sha256:94138682e68ec197db42ad7442d3cf9b328069c3ad8e4e5022e6b5cd3e7ffae5", - "sha256:968581d1717bbcf170758580f5f97a2925854943c45a19be4d47299507db2eb7", - "sha256:9d8d0642c63d453179058abc4143e30718b19a85cbf58c2744c9a63f06a1d388", - "sha256:a7ceb59986456ce851160867ce4929edaffbd2f069ae25717150199f8e1548b8", - "sha256:b9913c45d1be52d7a5db0c63977eebb51f68a2d5e6fd922d1d9b5e5fd758cc98", - "sha256:bde283313daf0b34a8d1bab30325f5cb0f4e11b5869dbe5bc61f8fe09a8f66f3", - "sha256:bf5b9c72b884c6f0c4ed26ef204ee1f768b9437330422492c319470954bc4cc7", - "sha256:ca80b121bbec76d7794fcb45e65a7eca660a76cc1a104ed439cdbd7df5f0b060", - "sha256:cdf66977a976d6a3cfb006afdf825d1482f84f7b81179db33941f2fc9673bb1d", - "sha256:d4faf846ed132fd7ebfbbf4fde588a62d21faa0faa06e6f468b7faa6f436b661", - "sha256:d7f87c2c02e03d99b95cfa6f7a776409083a9e4d468912e18c7680437b29222c", - "sha256:dd23df885318391856415e20acfd51a985cba6919f0be78ed89f5db9ff3a31cb", - "sha256:f5de3c676e57177b38857f6e3cdfbe8f38d1cd754b63200c0615eaa31f514b4f", - "sha256:f5e8e8d60e18d5f7fd49983f0c4696deeddaf6e608fbab33397671e2fcc6cc91", - "sha256:f7cac622e11b4253ac4536a654fe221249065d9a69feb6cdcd4d9af3503602e0", - "sha256:f8a04cf0c5b7139bc6368b461257d4a757ea2fe89b3773e494d235b7dd51119f", - "sha256:f8bb35ce57a63c9a6896c71a285818a3922d8ca05d150fd1fe49a7f57287b836", - "sha256:fbfdce91239fe306772faab57597186710d5699213f4df099d1612da7320d682" + "sha256:013150cc0f00f0a06dd898463ad9ebc43bd9c70c7fe35555c77d83fe6f758225", + "sha256:0814a5a7084e0bd357392e44e2a8bd72fc56fbdc3da0ff492ebb310c10fc95e6", + "sha256:103097b39764a0a02f1a051225ea6b4c64a53dd37603424ca8a1e09be63a460b", + "sha256:16bf432b274795b360d88b38cbffe0a6410450c94bfa172548bf1f512cf448c2", + "sha256:1a5012b7d047b16470063f0b8d003530e77362809f38cd7e601efb625c7ca71e", + "sha256:22bc6efb0f9fbb1c2e005ef1b94374568945c711bfb92f85916f66a819a5e6d0", + "sha256:377c02d0ddae3ebf843d6f453943602102bb186b09f1c78a2247e5dbf0e07b1c", + "sha256:421cfeacae2555b11318c6ee11f34bc0a9517657068d8911c916d55a85362ce2", + "sha256:44174aa4dae4db158e6f11a4ea696f1991d43ccc1634aa0c189daf03a9ced5d7", + "sha256:44dd79cfefea24f9bb630844a25047c3807e02722436e826ef2aed3d646190c1", + "sha256:4e3fbaf484ee68437f0ec589bdb1dd6f1dccc01fd6b72eac707e858b407521fa", + "sha256:4f0e6c49aac1c182be15a43d94e3b58c253d830c5b54dc93d6130e6987278611", + "sha256:539af6b66c6b9faca2cdd903f0a7564c85053f1faf95e9a37702df578ac37085", + "sha256:562b66d8b061b9cfae1bc704b0cd5d2b255628d86c3639ddc16e4ffa3ebf6e7a", + "sha256:5bb80c88f572a11156f258333c0e7b1f80d0746a03784600017901a2f1aa584a", + "sha256:5d1db7bc758455e6f6406d66e8b276b80dda5645877392a100d1ed7dda6aa7ad", + "sha256:618c4869e8140fd955b4620b10bc5a92ef1d62ae20aef38c1af7d892ee1bd996", + "sha256:6a93f249a40bda8c42cbeefff9582b22bb1dd769da56b4cbb824038366c4202c", + "sha256:6b9da562d7d7707d5561ecf4a27a361fd9f4856f39b8491a0753c89d8f39674c", + "sha256:73b65ee9a73a35fb68d96899895162beef19d86c1bcbe6f8f92eb0bd18c1d891", + "sha256:7b5f10ac866d3432a829a3a4446489be1fa3648f3140f9373fe99440a2e05682", + "sha256:81b4915081d148a31b64ad0314d2f609920b8ae6a24d9a7e4ddaab7c1fe998e7", + "sha256:90f9bc542f76efc56e5e76b420abaff42baf585db48a9fc0ac8edd6a16d9e60f", + "sha256:96e7bab9de56e0aca3858b8bc9c71f4eb0c0e12b7cf3cbfd170b62ce68cf71d7", + "sha256:975699ac5701d7ec1c633f2067deecea8711dc2a8683530aed260dd641274791", + "sha256:9f74faefea1acb398f057ed31ee9333e100bdae978b1e4c3b6a27d05df66e588", + "sha256:a11db551555c58606ed3dfe359a9a502e44350ed3ecbd59cbe7b0093bd020418", + "sha256:a6a04df4732bb7fdf9969ddee9a16a829e7971692fefdcb5baca760976d23e04", + "sha256:a72a7cb67764adafbac7ddeeffe539a738309068e2b2ac89cbd2f498383ce537", + "sha256:aabffb8b86fb95cb1ee5dffa315c9bd68fe20a7fe7260c0328679723b0257b7c", + "sha256:bc181db59d53e407650ebf44e63ff429c7bc25f9c346edddce1bdff1af436617", + "sha256:dd9c966e5fd8d7b0a54a130c5ad38ef581fd93ff4c44b6e73767519860da6ebe", + "sha256:ec800c25f09a7e031f2fbc3b17b4a4a0b54085c7532ac51b4c7ecef6d3ff8fc3", + "sha256:f0d6cfff74be4efcafecd374e094a8fed9e0d68efe90109d374ef5d8f18aa21a", + "sha256:f57b7a02e83d6e4a205cace6dd63e16b61a641a1da9366d9ec4f2b849430700f", + "sha256:fa190663f964583c8dbbab06bc863966e6f7eceaac8aa67c3ac0fae0a0a73b80", + "sha256:fa4cba4a8acbb71dd4215be8517879e4217c0746f7af2637330e7269694f53f2", + "sha256:fd9b670da1b7160e660cbba7f52e206892b97f61d8ff1872ce99dfaa9b475420" ], "index": "pypi", - "markers": "python_version >= '3.8'", - "version": "==24.2.1" + "markers": "python_version >= '3.9'", + "version": "==24.10.2" }, "greenlet": { "hashes": [ - "sha256:01bc7ea167cf943b4c802068e178bbf70ae2e8c080467070d01bfa02f337ee67", - "sha256:0448abc479fab28b00cb472d278828b3ccca164531daab4e970a0458786055d6", - "sha256:086152f8fbc5955df88382e8a75984e2bb1c892ad2e3c80a2508954e52295257", - "sha256:098d86f528c855ead3479afe84b49242e174ed262456c342d70fc7f972bc13c4", - "sha256:149e94a2dd82d19838fe4b2259f1b6b9957d5ba1b25640d2380bea9c5df37676", - "sha256:1551a8195c0d4a68fac7a4325efac0d541b48def35feb49d803674ac32582f61", - "sha256:15d79dd26056573940fcb8c7413d84118086f2ec1a8acdfa854631084393efcc", - "sha256:1996cb9306c8595335bb157d133daf5cf9f693ef413e7673cb07e3e5871379ca", - "sha256:1a7191e42732df52cb5f39d3527217e7ab73cae2cb3694d241e18f53d84ea9a7", - "sha256:1ea188d4f49089fc6fb283845ab18a2518d279c7cd9da1065d7a84e991748728", - "sha256:1f672519db1796ca0d8753f9e78ec02355e862d0998193038c7073045899f305", - "sha256:2516a9957eed41dd8f1ec0c604f1cdc86758b587d964668b5b196a9db5bfcde6", - "sha256:2797aa5aedac23af156bbb5a6aa2cd3427ada2972c828244eb7d1b9255846379", - "sha256:2dd6e660effd852586b6a8478a1d244b8dc90ab5b1321751d2ea15deb49ed414", - "sha256:3ddc0f794e6ad661e321caa8d2f0a55ce01213c74722587256fb6566049a8b04", - "sha256:3ed7fb269f15dc662787f4119ec300ad0702fa1b19d2135a37c2c4de6fadfd4a", - "sha256:419b386f84949bf0e7c73e6032e3457b82a787c1ab4a0e43732898a761cc9dbf", - "sha256:43374442353259554ce33599da8b692d5aa96f8976d567d4badf263371fbe491", - "sha256:52f59dd9c96ad2fc0d5724107444f76eb20aaccb675bf825df6435acb7703559", - "sha256:57e8974f23e47dac22b83436bdcf23080ade568ce77df33159e019d161ce1d1e", - "sha256:5b51e85cb5ceda94e79d019ed36b35386e8c37d22f07d6a751cb659b180d5274", - "sha256:649dde7de1a5eceb258f9cb00bdf50e978c9db1b996964cd80703614c86495eb", - "sha256:64d7675ad83578e3fc149b617a444fab8efdafc9385471f868eb5ff83e446b8b", - "sha256:68834da854554926fbedd38c76e60c4a2e3198c6fbed520b106a8986445caaf9", - "sha256:6b66c9c1e7ccabad3a7d037b2bcb740122a7b17a53734b7d72a344ce39882a1b", - "sha256:70fb482fdf2c707765ab5f0b6655e9cfcf3780d8d87355a063547b41177599be", - "sha256:7170375bcc99f1a2fbd9c306f5be8764eaf3ac6b5cb968862cad4c7057756506", - "sha256:73a411ef564e0e097dbe7e866bb2dda0f027e072b04da387282b02c308807405", - "sha256:77457465d89b8263bca14759d7c1684df840b6811b2499838cc5b040a8b5b113", - "sha256:7f362975f2d179f9e26928c5b517524e89dd48530a0202570d55ad6ca5d8a56f", - "sha256:81bb9c6d52e8321f09c3d165b2a78c680506d9af285bfccbad9fb7ad5a5da3e5", - "sha256:881b7db1ebff4ba09aaaeae6aa491daeb226c8150fc20e836ad00041bcb11230", - "sha256:894393ce10ceac937e56ec00bb71c4c2f8209ad516e96033e4b3b1de270e200d", - "sha256:99bf650dc5d69546e076f413a87481ee1d2d09aaaaaca058c9251b6d8c14783f", - "sha256:9da2bd29ed9e4f15955dd1595ad7bc9320308a3b766ef7f837e23ad4b4aac31a", - "sha256:afaff6cf5200befd5cec055b07d1c0a5a06c040fe5ad148abcd11ba6ab9b114e", - "sha256:b1b5667cced97081bf57b8fa1d6bfca67814b0afd38208d52538316e9422fc61", - "sha256:b37eef18ea55f2ffd8f00ff8fe7c8d3818abd3e25fb73fae2ca3b672e333a7a6", - "sha256:b542be2440edc2d48547b5923c408cbe0fc94afb9f18741faa6ae970dbcb9b6d", - "sha256:b7dcbe92cc99f08c8dd11f930de4d99ef756c3591a5377d1d9cd7dd5e896da71", - "sha256:b7f009caad047246ed379e1c4dbcb8b020f0a390667ea74d2387be2998f58a22", - "sha256:bba5387a6975598857d86de9eac14210a49d554a77eb8261cc68b7d082f78ce2", - "sha256:c5e1536de2aad7bf62e27baf79225d0d64360d4168cf2e6becb91baf1ed074f3", - "sha256:c5ee858cfe08f34712f548c3c363e807e7186f03ad7a5039ebadb29e8c6be067", - "sha256:c9db1c18f0eaad2f804728c67d6c610778456e3e1cc4ab4bbd5eeb8e6053c6fc", - "sha256:d353cadd6083fdb056bb46ed07e4340b0869c305c8ca54ef9da3421acbdf6881", - "sha256:d46677c85c5ba00a9cb6f7a00b2bfa6f812192d2c9f7d9c4f6a55b60216712f3", - "sha256:d4d1ac74f5c0c0524e4a24335350edad7e5f03b9532da7ea4d3c54d527784f2e", - "sha256:d73a9fe764d77f87f8ec26a0c85144d6a951a6c438dfe50487df5595c6373eac", - "sha256:da70d4d51c8b306bb7a031d5cff6cc25ad253affe89b70352af5f1cb68e74b53", - "sha256:daf3cb43b7cf2ba96d614252ce1684c1bccee6b2183a01328c98d36fcd7d5cb0", - "sha256:dca1e2f3ca00b84a396bc1bce13dd21f680f035314d2379c4160c98153b2059b", - "sha256:dd4f49ae60e10adbc94b45c0b5e6a179acc1736cf7a90160b404076ee283cf83", - "sha256:e1f145462f1fa6e4a4ae3c0f782e580ce44d57c8f2c7aae1b6fa88c0b2efdb41", - "sha256:e3391d1e16e2a5a1507d83e4a8b100f4ee626e8eca43cf2cadb543de69827c4c", - "sha256:fcd2469d6a2cf298f198f0487e0a5b1a47a42ca0fa4dfd1b6862c999f018ebbf", - "sha256:fd096eb7ffef17c456cfa587523c5f92321ae02427ff955bebe9e3c63bc9f0da", - "sha256:fe754d231288e1e64323cfad462fcee8f0288654c10bdf4f603a39ed923bef33" + "sha256:0153404a4bb921f0ff1abeb5ce8a5131da56b953eda6e14b88dc6bbc04d2049e", + "sha256:03a088b9de532cbfe2ba2034b2b85e82df37874681e8c470d6fb2f8c04d7e4b7", + "sha256:04b013dc07c96f83134b1e99888e7a79979f1a247e2a9f59697fa14b5862ed01", + "sha256:05175c27cb459dcfc05d026c4232f9de8913ed006d42713cb8a5137bd49375f1", + "sha256:09fc016b73c94e98e29af67ab7b9a879c307c6731a2c9da0db5a7d9b7edd1159", + "sha256:0bbae94a29c9e5c7e4a2b7f0aae5c17e8e90acbfd3bf6270eeba60c39fce3563", + "sha256:0fde093fb93f35ca72a556cf72c92ea3ebfda3d79fc35bb19fbe685853869a83", + "sha256:1443279c19fca463fc33e65ef2a935a5b09bb90f978beab37729e1c3c6c25fe9", + "sha256:1776fd7f989fc6b8d8c8cb8da1f6b82c5814957264d1f6cf818d475ec2bf6395", + "sha256:1d3755bcb2e02de341c55b4fca7a745a24a9e7212ac953f6b3a48d117d7257aa", + "sha256:23f20bb60ae298d7d8656c6ec6db134bca379ecefadb0b19ce6f19d1f232a942", + "sha256:275f72decf9932639c1c6dd1013a1bc266438eb32710016a1c742df5da6e60a1", + "sha256:2846930c65b47d70b9d178e89c7e1a69c95c1f68ea5aa0a58646b7a96df12441", + "sha256:3319aa75e0e0639bc15ff54ca327e8dc7a6fe404003496e3c6925cd3142e0e22", + "sha256:346bed03fe47414091be4ad44786d1bd8bef0c3fcad6ed3dee074a032ab408a9", + "sha256:36b89d13c49216cadb828db8dfa6ce86bbbc476a82d3a6c397f0efae0525bdd0", + "sha256:37b9de5a96111fc15418819ab4c4432e4f3c2ede61e660b1e33971eba26ef9ba", + "sha256:396979749bd95f018296af156201d6211240e7a23090f50a8d5d18c370084dc3", + "sha256:3b2813dc3de8c1ee3f924e4d4227999285fd335d1bcc0d2be6dc3f1f6a318ec1", + "sha256:411f015496fec93c1c8cd4e5238da364e1da7a124bcb293f085bf2860c32c6f6", + "sha256:47da355d8687fd65240c364c90a31569a133b7b60de111c255ef5b606f2ae291", + "sha256:48ca08c771c268a768087b408658e216133aecd835c0ded47ce955381105ba39", + "sha256:4afe7ea89de619adc868e087b4d2359282058479d7cfb94970adf4b55284574d", + "sha256:4ce3ac6cdb6adf7946475d7ef31777c26d94bccc377e070a7986bd2d5c515467", + "sha256:4ead44c85f8ab905852d3de8d86f6f8baf77109f9da589cb4fa142bd3b57b475", + "sha256:54558ea205654b50c438029505def3834e80f0869a70fb15b871c29b4575ddef", + "sha256:5e06afd14cbaf9e00899fae69b24a32f2196c19de08fcb9f4779dd4f004e5e7c", + "sha256:62ee94988d6b4722ce0028644418d93a52429e977d742ca2ccbe1c4f4a792511", + "sha256:63e4844797b975b9af3a3fb8f7866ff08775f5426925e1e0bbcfe7932059a12c", + "sha256:6510bf84a6b643dabba74d3049ead221257603a253d0a9873f55f6a59a65f822", + "sha256:667a9706c970cb552ede35aee17339a18e8f2a87a51fba2ed39ceeeb1004798a", + "sha256:6ef9ea3f137e5711f0dbe5f9263e8c009b7069d8a1acea822bd5e9dae0ae49c8", + "sha256:7017b2be767b9d43cc31416aba48aab0d2309ee31b4dbf10a1d38fb7972bdf9d", + "sha256:7124e16b4c55d417577c2077be379514321916d5790fa287c9ed6f23bd2ffd01", + "sha256:73aaad12ac0ff500f62cebed98d8789198ea0e6f233421059fa68a5aa7220145", + "sha256:77c386de38a60d1dfb8e55b8c1101d68c79dfdd25c7095d51fec2dd800892b80", + "sha256:7876452af029456b3f3549b696bb36a06db7c90747740c5302f74a9e9fa14b13", + "sha256:7939aa3ca7d2a1593596e7ac6d59391ff30281ef280d8632fa03d81f7c5f955e", + "sha256:8320f64b777d00dd7ccdade271eaf0cad6636343293a25074cc5566160e4de7b", + "sha256:85f3ff71e2e60bd4b4932a043fbbe0f499e263c628390b285cb599154a3b03b1", + "sha256:8b8b36671f10ba80e159378df9c4f15c14098c4fd73a36b9ad715f057272fbef", + "sha256:93147c513fac16385d1036b7e5b102c7fbbdb163d556b791f0f11eada7ba65dc", + "sha256:935e943ec47c4afab8965954bf49bfa639c05d4ccf9ef6e924188f762145c0ff", + "sha256:94b6150a85e1b33b40b1464a3f9988dcc5251d6ed06842abff82e42632fac120", + "sha256:94ebba31df2aa506d7b14866fed00ac141a867e63143fe5bca82a8e503b36437", + "sha256:95ffcf719966dd7c453f908e208e14cde192e09fde6c7186c8f1896ef778d8cd", + "sha256:98884ecf2ffb7d7fe6bd517e8eb99d31ff7855a840fa6d0d63cd07c037f6a981", + "sha256:99cfaa2110534e2cf3ba31a7abcac9d328d1d9f1b95beede58294a60348fba36", + "sha256:9e8f8c9cb53cdac7ba9793c276acd90168f416b9ce36799b9b885790f8ad6c0a", + "sha256:a0dfc6c143b519113354e780a50381508139b07d2177cb6ad6a08278ec655798", + "sha256:b2795058c23988728eec1f36a4e5e4ebad22f8320c85f3587b539b9ac84128d7", + "sha256:b42703b1cf69f2aa1df7d1030b9d77d3e584a70755674d60e710f0af570f3761", + "sha256:b7cede291382a78f7bb5f04a529cb18e068dd29e0fb27376074b6d0317bf4dd0", + "sha256:b8a678974d1f3aa55f6cc34dc480169d58f2e6d8958895d68845fa4ab566509e", + "sha256:b8da394b34370874b4572676f36acabac172602abf054cbc4ac910219f3340af", + "sha256:c3a701fe5a9695b238503ce5bbe8218e03c3bcccf7e204e455e7462d770268aa", + "sha256:c4aab7f6381f38a4b42f269057aee279ab0fc7bf2e929e3d4abfae97b682a12c", + "sha256:ca9d0ff5ad43e785350894d97e13633a66e2b50000e8a183a50a88d834752d42", + "sha256:d0028e725ee18175c6e422797c407874da24381ce0690d6b9396c204c7f7276e", + "sha256:d21e10da6ec19b457b82636209cbe2331ff4306b54d06fa04b7c138ba18c8a81", + "sha256:d5e975ca70269d66d17dd995dafc06f1b06e8cb1ec1e9ed54c1d1e4a7c4cf26e", + "sha256:da7a9bff22ce038e19bf62c4dd1ec8391062878710ded0a845bcf47cc0200617", + "sha256:db32b5348615a04b82240cc67983cb315309e88d444a288934ee6ceaebcad6cc", + "sha256:dcc62f31eae24de7f8dce72134c8651c58000d3b1868e01392baea7c32c247de", + "sha256:dfc59d69fc48664bc693842bd57acfdd490acafda1ab52c7836e3fc75c90a111", + "sha256:e347b3bfcf985a05e8c0b7d462ba6f15b1ee1c909e2dcad795e49e91b152c383", + "sha256:e4d333e558953648ca09d64f13e6d8f0523fa705f51cae3f03b5983489958c70", + "sha256:ed10eac5830befbdd0c32f83e8aa6288361597550ba669b04c48f0f9a2c843c6", + "sha256:efc0f674aa41b92da8c49e0346318c6075d734994c3c4e4430b1c3f853e498e4", + "sha256:f1695e76146579f8c06c1509c7ce4dfe0706f49c6831a817ac04eebb2fd02011", + "sha256:f1d4aeb8891338e60d1ab6127af1fe45def5259def8094b9c7e34690c8858803", + "sha256:f406b22b7c9a9b4f8aa9d2ab13d6ae0ac3e85c9a809bd590ad53fed2bf70dc79", + "sha256:f6ff3b14f2df4c41660a7dec01045a045653998784bf8cfcb5a525bdffffbc8f" ], "index": "pypi", "markers": "python_version >= '3.7'", - "version": "==3.0.3" + "version": "==3.1.1" }, "gunicorn": { "hashes": [ @@ -865,49 +718,13 @@ "markers": "python_version >= '3.7'", "version": "==23.0.0" }, - "h5py": { - "hashes": [ - "sha256:083e0329ae534a264940d6513f47f5ada617da536d8dccbafc3026aefc33c90e", - "sha256:1625fd24ad6cfc9c1ccd44a66dac2396e7ee74940776792772819fc69f3a3731", - "sha256:21dbdc5343f53b2e25404673c4f00a3335aef25521bd5fa8c707ec3833934892", - "sha256:52c416f8eb0daae39dabe71415cb531f95dce2d81e1f61a74537a50c63b28ab3", - "sha256:55106b04e2c83dfb73dc8732e9abad69d83a436b5b82b773481d95d17b9685e1", - "sha256:67462d0669f8f5459529de179f7771bd697389fcb3faab54d63bf788599a48ea", - "sha256:6c4b760082626120031d7902cd983d8c1f424cdba2809f1067511ef283629d4b", - "sha256:731839240c59ba219d4cb3bc5880d438248533366f102402cfa0621b71796b62", - "sha256:754c0c2e373d13d6309f408325343b642eb0f40f1a6ad21779cfa9502209e150", - "sha256:75bd7b3d93fbeee40860fd70cdc88df4464e06b70a5ad9ce1446f5f32eb84007", - "sha256:77b19a40788e3e362b54af4dcf9e6fde59ca016db2c61360aa30b47c7b7cef00", - "sha256:7b7e8f78072a2edec87c9836f25f34203fd492a4475709a18b417a33cfb21fa9", - "sha256:8ec9df3dd2018904c4cc06331951e274f3f3fd091e6d6cc350aaa90fa9b42a76", - "sha256:a76cae64080210389a571c7d13c94a1a6cf8cb75153044fd1f822a962c97aeab", - "sha256:aa6ae84a14103e8dc19266ef4c3e5d7c00b68f21d07f2966f0ca7bdb6c2761fb", - "sha256:bbd732a08187a9e2a6ecf9e8af713f1d68256ee0f7c8b652a32795670fb481ba", - "sha256:c072655ad1d5fe9ef462445d3e77a8166cbfa5e599045f8aa3c19b75315f10e5", - "sha256:d9c944d364688f827dc889cf83f1fca311caf4fa50b19f009d1f2b525edd33a3", - "sha256:ef4e2f338fc763f50a8113890f455e1a70acd42a4d083370ceb80c463d803972", - "sha256:f3736fe21da2b7d8a13fe8fe415f1272d2a1ccdeff4849c1421d2fb30fd533bc", - "sha256:f4e025e852754ca833401777c25888acb96889ee2c27e7e629a19aee288833f0" - ], - "index": "pypi", - "markers": "python_version >= '3.8'", - "version": "==3.11.0" - }, - "huggingface-hub": { - "hashes": [ - "sha256:a990f3232aa985fe749bc9474060cbad75e8b2f115f6665a9fda5b9c97818970", - "sha256:cc2579e761d070713eaa9c323e3debe39d5b464ae3a7261c39a9195b27bb8000" - ], - "markers": "python_full_version >= '3.8.0'", - "version": "==0.24.6" - }, "idna": { "hashes": [ - "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc", - "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0" + "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", + "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3" ], - "markers": "python_version >= '3.5'", - "version": "==3.7" + "markers": "python_version >= '3.6'", + "version": "==3.10" }, "itsdangerous": { "hashes": [ @@ -933,14 +750,6 @@ "markers": "python_version >= '3.7'", "version": "==1.0.1" }, - "joblib": { - "hashes": [ - "sha256:06d478d5674cbc267e7496a410ee875abd68e4340feff4490bcb7afb88060ae6", - "sha256:2382c5816b2636fbd20a09e0f4e9dad4736765fdfb7dca582943b9c1366b3f0e" - ], - "markers": "python_version >= '3.8'", - "version": "==1.4.2" - }, "jsonschema": { "hashes": [ "sha256:d71497fef26351a33265337fa77ffeb82423f3ea21283cd9467bb03999266bc4", @@ -951,11 +760,11 @@ }, "jsonschema-specifications": { "hashes": [ - "sha256:48a76787b3e70f5ed53f1160d2b81f586e4ca6d1548c5de7085d1682674764cc", - "sha256:87e4fdf3a94858b8a2ba2778d9ba57d8a9cafca7c7489c46ba0d30a8bc6a9c3c" + "sha256:0f38b83639958ce1152d02a7f062902c41c8fd20d558b0c34344292d417ae272", + "sha256:a09a0680616357d9a0ecf05c12ad234479f549239d0f5b55f3deea67475da9bf" ], - "markers": "python_version >= '3.8'", - "version": "==2023.12.1" + "markers": "python_version >= '3.9'", + "version": "==2024.10.1" }, "jwt": { "hashes": [ @@ -965,237 +774,81 @@ "markers": "python_version >= '3.6'", "version": "==1.3.1" }, - "kiwisolver": { - "hashes": [ - "sha256:00bd361b903dc4bbf4eb165f24d1acbee754fce22ded24c3d56eec268658a5cf", - "sha256:040c1aebeda72197ef477a906782b5ab0d387642e93bda547336b8957c61022e", - "sha256:05703cf211d585109fcd72207a31bb170a0f22144d68298dc5e61b3c946518af", - "sha256:06f54715b7737c2fecdbf140d1afb11a33d59508a47bf11bb38ecf21dc9ab79f", - "sha256:0dc9db8e79f0036e8173c466d21ef18e1befc02de8bf8aa8dc0813a6dc8a7046", - "sha256:0f114aa76dc1b8f636d077979c0ac22e7cd8f3493abbab152f20eb8d3cda71f3", - "sha256:11863aa14a51fd6ec28688d76f1735f8f69ab1fabf388851a595d0721af042f5", - "sha256:11c7de8f692fc99816e8ac50d1d1aef4f75126eefc33ac79aac02c099fd3db71", - "sha256:11d011a7574eb3b82bcc9c1a1d35c1d7075677fdd15de527d91b46bd35e935ee", - "sha256:146d14bebb7f1dc4d5fbf74f8a6cb15ac42baadee8912eb84ac0b3b2a3dc6ac3", - "sha256:15568384086b6df3c65353820a4473575dbad192e35010f622c6ce3eebd57af9", - "sha256:19df6e621f6d8b4b9c4d45f40a66839294ff2bb235e64d2178f7522d9170ac5b", - "sha256:1b04139c4236a0f3aff534479b58f6f849a8b351e1314826c2d230849ed48985", - "sha256:210ef2c3a1f03272649aff1ef992df2e724748918c4bc2d5a90352849eb40bea", - "sha256:2270953c0d8cdab5d422bee7d2007f043473f9d2999631c86a223c9db56cbd16", - "sha256:2400873bccc260b6ae184b2b8a4fec0e4082d30648eadb7c3d9a13405d861e89", - "sha256:2a40773c71d7ccdd3798f6489aaac9eee213d566850a9533f8d26332d626b82c", - "sha256:2c5674c4e74d939b9d91dda0fae10597ac7521768fec9e399c70a1f27e2ea2d9", - "sha256:3195782b26fc03aa9c6913d5bad5aeb864bdc372924c093b0f1cebad603dd712", - "sha256:31a82d498054cac9f6d0b53d02bb85811185bcb477d4b60144f915f3b3126342", - "sha256:32d5cf40c4f7c7b3ca500f8985eb3fb3a7dfc023215e876f207956b5ea26632a", - "sha256:346f5343b9e3f00b8db8ba359350eb124b98c99efd0b408728ac6ebf38173958", - "sha256:378a214a1e3bbf5ac4a8708304318b4f890da88c9e6a07699c4ae7174c09a68d", - "sha256:39b42c68602539407884cf70d6a480a469b93b81b7701378ba5e2328660c847a", - "sha256:3a2b053a0ab7a3960c98725cfb0bf5b48ba82f64ec95fe06f1d06c99b552e130", - "sha256:3aba7311af82e335dd1e36ffff68aaca609ca6290c2cb6d821a39aa075d8e3ff", - "sha256:3cd32d6c13807e5c66a7cbb79f90b553642f296ae4518a60d8d76243b0ad2898", - "sha256:3edd2fa14e68c9be82c5b16689e8d63d89fe927e56debd6e1dbce7a26a17f81b", - "sha256:4c380469bd3f970ef677bf2bcba2b6b0b4d5c75e7a020fb863ef75084efad66f", - "sha256:4e66e81a5779b65ac21764c295087de82235597a2293d18d943f8e9e32746265", - "sha256:53abb58632235cd154176ced1ae8f0d29a6657aa1aa9decf50b899b755bc2b93", - "sha256:5794cf59533bc3f1b1c821f7206a3617999db9fbefc345360aafe2e067514929", - "sha256:59415f46a37f7f2efeec758353dd2eae1b07640d8ca0f0c42548ec4125492635", - "sha256:59ec7b7c7e1a61061850d53aaf8e93db63dce0c936db1fda2658b70e4a1be709", - "sha256:59edc41b24031bc25108e210c0def6f6c2191210492a972d585a06ff246bb79b", - "sha256:5a580c91d686376f0f7c295357595c5a026e6cbc3d77b7c36e290201e7c11ecb", - "sha256:5b94529f9b2591b7af5f3e0e730a4e0a41ea174af35a4fd067775f9bdfeee01a", - "sha256:5c7b3b3a728dc6faf3fc372ef24f21d1e3cee2ac3e9596691d746e5a536de920", - "sha256:5c90ae8c8d32e472be041e76f9d2f2dbff4d0b0be8bd4041770eddb18cf49a4e", - "sha256:5e7139af55d1688f8b960ee9ad5adafc4ac17c1c473fe07133ac092310d76544", - "sha256:5ff5cf3571589b6d13bfbfd6bcd7a3f659e42f96b5fd1c4830c4cf21d4f5ef45", - "sha256:620ced262a86244e2be10a676b646f29c34537d0d9cc8eb26c08f53d98013390", - "sha256:6512cb89e334e4700febbffaaa52761b65b4f5a3cf33f960213d5656cea36a77", - "sha256:6c08e1312a9cf1074d17b17728d3dfce2a5125b2d791527f33ffbe805200a355", - "sha256:6c3bd3cde54cafb87d74d8db50b909705c62b17c2099b8f2e25b461882e544ff", - "sha256:6ef7afcd2d281494c0a9101d5c571970708ad911d028137cd558f02b851c08b4", - "sha256:7269d9e5f1084a653d575c7ec012ff57f0c042258bf5db0954bf551c158466e7", - "sha256:72d40b33e834371fd330fb1472ca19d9b8327acb79a5821d4008391db8e29f20", - "sha256:74d1b44c6cfc897df648cc9fdaa09bc3e7679926e6f96df05775d4fb3946571c", - "sha256:74db36e14a7d1ce0986fa104f7d5637aea5c82ca6326ed0ec5694280942d1162", - "sha256:763773d53f07244148ccac5b084da5adb90bfaee39c197554f01b286cf869228", - "sha256:76c6a5964640638cdeaa0c359382e5703e9293030fe730018ca06bc2010c4437", - "sha256:76d9289ed3f7501012e05abb8358bbb129149dbd173f1f57a1bf1c22d19ab7cc", - "sha256:7931d8f1f67c4be9ba1dd9c451fb0eeca1a25b89e4d3f89e828fe12a519b782a", - "sha256:7b8b454bac16428b22560d0a1cf0a09875339cab69df61d7805bf48919415901", - "sha256:7e5bab140c309cb3a6ce373a9e71eb7e4873c70c2dda01df6820474f9889d6d4", - "sha256:83d78376d0d4fd884e2c114d0621624b73d2aba4e2788182d286309ebdeed770", - "sha256:852542f9481f4a62dbb5dd99e8ab7aedfeb8fb6342349a181d4036877410f525", - "sha256:85267bd1aa8880a9c88a8cb71e18d3d64d2751a790e6ca6c27b8ccc724bcd5ad", - "sha256:88a2df29d4724b9237fc0c6eaf2a1adae0cdc0b3e9f4d8e7dc54b16812d2d81a", - "sha256:88b9f257ca61b838b6f8094a62418421f87ac2a1069f7e896c36a7d86b5d4c29", - "sha256:8ab3919a9997ab7ef2fbbed0cc99bb28d3c13e6d4b1ad36e97e482558a91be90", - "sha256:92dea1ffe3714fa8eb6a314d2b3c773208d865a0e0d35e713ec54eea08a66250", - "sha256:9407b6a5f0d675e8a827ad8742e1d6b49d9c1a1da5d952a67d50ef5f4170b18d", - "sha256:9408acf3270c4b6baad483865191e3e582b638b1654a007c62e3efe96f09a9a3", - "sha256:955e8513d07a283056b1396e9a57ceddbd272d9252c14f154d450d227606eb54", - "sha256:9db8ea4c388fdb0f780fe91346fd438657ea602d58348753d9fb265ce1bca67f", - "sha256:9eaa8b117dc8337728e834b9c6e2611f10c79e38f65157c4c38e9400286f5cb1", - "sha256:a51a263952b1429e429ff236d2f5a21c5125437861baeed77f5e1cc2d2c7c6da", - "sha256:a6aa6315319a052b4ee378aa171959c898a6183f15c1e541821c5c59beaa0238", - "sha256:aa12042de0171fad672b6c59df69106d20d5596e4f87b5e8f76df757a7c399aa", - "sha256:aaf7be1207676ac608a50cd08f102f6742dbfc70e8d60c4db1c6897f62f71523", - "sha256:b0157420efcb803e71d1b28e2c287518b8808b7cf1ab8af36718fd0a2c453eb0", - "sha256:b3f7e75f3015df442238cca659f8baa5f42ce2a8582727981cbfa15fee0ee205", - "sha256:b9098e0049e88c6a24ff64545cdfc50807818ba6c1b739cae221bbbcbc58aad3", - "sha256:ba55dce0a9b8ff59495ddd050a0225d58bd0983d09f87cfe2b6aec4f2c1234e4", - "sha256:bb86433b1cfe686da83ce32a9d3a8dd308e85c76b60896d58f082136f10bffac", - "sha256:bbea0db94288e29afcc4c28afbf3a7ccaf2d7e027489c449cf7e8f83c6346eb9", - "sha256:bbf1d63eef84b2e8c89011b7f2235b1e0bf7dacc11cac9431fc6468e99ac77fb", - "sha256:c7940c1dc63eb37a67721b10d703247552416f719c4188c54e04334321351ced", - "sha256:c9bf3325c47b11b2e51bca0824ea217c7cd84491d8ac4eefd1e409705ef092bd", - "sha256:cdc8a402aaee9a798b50d8b827d7ecf75edc5fb35ea0f91f213ff927c15f4ff0", - "sha256:ceec1a6bc6cab1d6ff5d06592a91a692f90ec7505d6463a88a52cc0eb58545da", - "sha256:cfe6ab8da05c01ba6fbea630377b5da2cd9bcbc6338510116b01c1bc939a2c18", - "sha256:d099e745a512f7e3bbe7249ca835f4d357c586d78d79ae8f1dcd4d8adeb9bda9", - "sha256:d0ef46024e6a3d79c01ff13801cb19d0cad7fd859b15037aec74315540acc276", - "sha256:d2e5a98f0ec99beb3c10e13b387f8db39106d53993f498b295f0c914328b1333", - "sha256:da4cfb373035def307905d05041c1d06d8936452fe89d464743ae7fb8371078b", - "sha256:da802a19d6e15dffe4b0c24b38b3af68e6c1a68e6e1d8f30148c83864f3881db", - "sha256:dced8146011d2bc2e883f9bd68618b8247387f4bbec46d7392b3c3b032640126", - "sha256:dfdd7c0b105af050eb3d64997809dc21da247cf44e63dc73ff0fd20b96be55a9", - "sha256:e368f200bbc2e4f905b8e71eb38b3c04333bddaa6a2464a6355487b02bb7fb09", - "sha256:e391b1f0a8a5a10ab3b9bb6afcfd74f2175f24f8975fb87ecae700d1503cdee0", - "sha256:e57e563a57fb22a142da34f38acc2fc1a5c864bc29ca1517a88abc963e60d6ec", - "sha256:e5d706eba36b4c4d5bc6c6377bb6568098765e990cfc21ee16d13963fab7b3e7", - "sha256:ec20916e7b4cbfb1f12380e46486ec4bcbaa91a9c448b97023fde0d5bbf9e4ff", - "sha256:f1d072c2eb0ad60d4c183f3fb44ac6f73fb7a8f16a2694a91f988275cbf352f9", - "sha256:f846c260f483d1fd217fe5ed7c173fb109efa6b1fc8381c8b7552c5781756192", - "sha256:f91de7223d4c7b793867797bacd1ee53bfe7359bd70d27b7b58a04efbb9436c8", - "sha256:faae4860798c31530dd184046a900e652c95513796ef51a12bc086710c2eec4d", - "sha256:fc579bf0f502e54926519451b920e875f433aceb4624a3646b3252b5caa9e0b6", - "sha256:fcc700eadbbccbf6bc1bcb9dbe0786b4b1cb91ca0dcda336eef5c2beed37b797", - "sha256:fd32ea360bcbb92d28933fc05ed09bffcb1704ba3fc7942e81db0fd4f81a7892", - "sha256:fdb7adb641a0d13bdcd4ef48e062363d8a9ad4a182ac7647ec88f695e719ae9f" - ], - "markers": "python_version >= '3.7'", - "version": "==1.4.5" - }, "markupsafe": { "hashes": [ - "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf", - "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff", - "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f", - "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3", - "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532", - "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f", - "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617", - "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df", - "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4", - "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906", - "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f", - "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4", - "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8", - "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371", - "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2", - "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465", - "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52", - "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6", - "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169", - "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad", - "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2", - "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0", - "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029", - "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f", - "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a", - "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced", - "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5", - "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c", - "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf", - "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9", - "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb", - "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad", - "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3", - "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1", - "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46", - "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc", - "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a", - "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee", - "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900", - "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5", - "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea", - "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f", - "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5", - "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e", - "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a", - "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f", - "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50", - "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a", - "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b", - "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4", - "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff", - "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2", - "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46", - "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b", - "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf", - "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5", - "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5", - "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab", - "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd", - "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68" + "sha256:0778de17cff1acaeccc3ff30cd99a3fd5c50fc58ad3d6c0e0c4c58092b859396", + "sha256:0f84af7e813784feb4d5e4ff7db633aba6c8ca64a833f61d8e4eade234ef0c38", + "sha256:17b2aea42a7280db02ac644db1d634ad47dcc96faf38ab304fe26ba2680d359a", + "sha256:242d6860f1fd9191aef5fae22b51c5c19767f93fb9ead4d21924e0bcb17619d8", + "sha256:244dbe463d5fb6d7ce161301a03a6fe744dac9072328ba9fc82289238582697b", + "sha256:26627785a54a947f6d7336ce5963569b5d75614619e75193bdb4e06e21d447ad", + "sha256:2a4b34a8d14649315c4bc26bbfa352663eb51d146e35eef231dd739d54a5430a", + "sha256:2ae99f31f47d849758a687102afdd05bd3d3ff7dbab0a8f1587981b58a76152a", + "sha256:312387403cd40699ab91d50735ea7a507b788091c416dd007eac54434aee51da", + "sha256:3341c043c37d78cc5ae6e3e305e988532b072329639007fd408a476642a89fd6", + "sha256:33d1c36b90e570ba7785dacd1faaf091203d9942bc036118fab8110a401eb1a8", + "sha256:3e683ee4f5d0fa2dde4db77ed8dd8a876686e3fc417655c2ece9a90576905344", + "sha256:3ffb4a8e7d46ed96ae48805746755fadd0909fea2306f93d5d8233ba23dda12a", + "sha256:40621d60d0e58aa573b68ac5e2d6b20d44392878e0bfc159012a5787c4e35bc8", + "sha256:40f1e10d51c92859765522cbd79c5c8989f40f0419614bcdc5015e7b6bf97fc5", + "sha256:45d42d132cff577c92bfba536aefcfea7e26efb975bd455db4e6602f5c9f45e7", + "sha256:48488d999ed50ba8d38c581d67e496f955821dc183883550a6fbc7f1aefdc170", + "sha256:4935dd7883f1d50e2ffecca0aa33dc1946a94c8f3fdafb8df5c330e48f71b132", + "sha256:4c2d64fdba74ad16138300815cfdc6ab2f4647e23ced81f59e940d7d4a1469d9", + "sha256:4c8817557d0de9349109acb38b9dd570b03cc5014e8aabf1cbddc6e81005becd", + "sha256:4ffaaac913c3f7345579db4f33b0020db693f302ca5137f106060316761beea9", + "sha256:5a4cb365cb49b750bdb60b846b0c0bc49ed62e59a76635095a179d440540c346", + "sha256:62fada2c942702ef8952754abfc1a9f7658a4d5460fabe95ac7ec2cbe0d02abc", + "sha256:67c519635a4f64e495c50e3107d9b4075aec33634272b5db1cde839e07367589", + "sha256:6a54c43d3ec4cf2a39f4387ad044221c66a376e58c0d0e971d47c475ba79c6b5", + "sha256:7044312a928a66a4c2a22644147bc61a199c1709712069a344a3fb5cfcf16915", + "sha256:730d86af59e0e43ce277bb83970530dd223bf7f2a838e086b50affa6ec5f9295", + "sha256:800100d45176652ded796134277ecb13640c1a537cad3b8b53da45aa96330453", + "sha256:80fcbf3add8790caddfab6764bde258b5d09aefbe9169c183f88a7410f0f6dea", + "sha256:82b5dba6eb1bcc29cc305a18a3c5365d2af06ee71b123216416f7e20d2a84e5b", + "sha256:852dc840f6d7c985603e60b5deaae1d89c56cb038b577f6b5b8c808c97580f1d", + "sha256:8ad4ad1429cd4f315f32ef263c1342166695fad76c100c5d979c45d5570ed58b", + "sha256:8ae369e84466aa70f3154ee23c1451fda10a8ee1b63923ce76667e3077f2b0c4", + "sha256:93e8248d650e7e9d49e8251f883eed60ecbc0e8ffd6349e18550925e31bd029b", + "sha256:973a371a55ce9ed333a3a0f8e0bcfae9e0d637711534bcb11e130af2ab9334e7", + "sha256:9ba25a71ebf05b9bb0e2ae99f8bc08a07ee8e98c612175087112656ca0f5c8bf", + "sha256:a10860e00ded1dd0a65b83e717af28845bb7bd16d8ace40fe5531491de76b79f", + "sha256:a4792d3b3a6dfafefdf8e937f14906a51bd27025a36f4b188728a73382231d91", + "sha256:a7420ceda262dbb4b8d839a4ec63d61c261e4e77677ed7c66c99f4e7cb5030dd", + "sha256:ad91738f14eb8da0ff82f2acd0098b6257621410dcbd4df20aaa5b4233d75a50", + "sha256:b6a387d61fe41cdf7ea95b38e9af11cfb1a63499af2759444b99185c4ab33f5b", + "sha256:b954093679d5750495725ea6f88409946d69cfb25ea7b4c846eef5044194f583", + "sha256:bbde71a705f8e9e4c3e9e33db69341d040c827c7afa6789b14c6e16776074f5a", + "sha256:beeebf760a9c1f4c07ef6a53465e8cfa776ea6a2021eda0d0417ec41043fe984", + "sha256:c91b394f7601438ff79a4b93d16be92f216adb57d813a78be4446fe0f6bc2d8c", + "sha256:c97ff7fedf56d86bae92fa0a646ce1a0ec7509a7578e1ed238731ba13aabcd1c", + "sha256:cb53e2a99df28eee3b5f4fea166020d3ef9116fdc5764bc5117486e6d1211b25", + "sha256:cbf445eb5628981a80f54087f9acdbf84f9b7d862756110d172993b9a5ae81aa", + "sha256:d06b24c686a34c86c8c1fba923181eae6b10565e4d80bdd7bc1c8e2f11247aa4", + "sha256:d98e66a24497637dd31ccab090b34392dddb1f2f811c4b4cd80c230205c074a3", + "sha256:db15ce28e1e127a0013dfb8ac243a8e392db8c61eae113337536edb28bdc1f97", + "sha256:db842712984e91707437461930e6011e60b39136c7331e971952bb30465bc1a1", + "sha256:e24bfe89c6ac4c31792793ad9f861b8f6dc4546ac6dc8f1c9083c7c4f2b335cd", + "sha256:e81c52638315ff4ac1b533d427f50bc0afc746deb949210bc85f05d4f15fd772", + "sha256:e9393357f19954248b00bed7c56f29a25c930593a77630c719653d51e7669c2a", + "sha256:ee3941769bd2522fe39222206f6dd97ae83c442a94c90f2b7a25d847d40f4729", + "sha256:f31ae06f1328595d762c9a2bf29dafd8621c7d3adc130cbb46278079758779ca", + "sha256:f94190df587738280d544971500b9cafc9b950d32efcb1fba9ac10d84e6aa4e6", + "sha256:fa7d686ed9883f3d664d39d5a8e74d3c5f63e603c2e3ff0abcba23eac6542635", + "sha256:fb532dd9900381d2e8f48172ddc5a59db4c445a11b9fab40b3b786da40d3b56b", + "sha256:fe32482b37b4b00c7a52a07211b479653b7fe4f22b2e481b9a9b099d8a430f2f" ], - "markers": "python_version >= '3.7'", - "version": "==2.1.5" - }, - "matplotlib": { - "hashes": [ - "sha256:039082812cacd6c6bec8e17a9c1e6baca230d4116d522e81e1f63a74d01d2e21", - "sha256:03ba9c1299c920964e8d3857ba27173b4dbb51ca4bab47ffc2c2ba0eb5e2cbc5", - "sha256:050598c2b29e0b9832cde72bcf97627bf00262adbc4a54e2b856426bb2ef0697", - "sha256:18128cc08f0d3cfff10b76baa2f296fc28c4607368a8402de61bb3f2eb33c7d9", - "sha256:1cd93b91ab47a3616b4d3c42b52f8363b88ca021e340804c6ab2536344fad9ca", - "sha256:1d94ff717eb2bd0b58fe66380bd8b14ac35f48a98e7c6765117fe67fb7684e64", - "sha256:306c8dfc73239f0e72ac50e5a9cf19cc4e8e331dd0c54f5e69ca8758550f1e1e", - "sha256:37e51dd1c2db16ede9cfd7b5cabdfc818b2c6397c83f8b10e0e797501c963a03", - "sha256:3fd595f34aa8a55b7fc8bf9ebea8aa665a84c82d275190a61118d33fbc82ccae", - "sha256:4876d7d40219e8ae8bb70f9263bcbe5714415acfdf781086601211335e24f8aa", - "sha256:5413401594cfaff0052f9d8b1aafc6d305b4bd7c4331dccd18f561ff7e1d3bd3", - "sha256:5816b1e1fe8c192cbc013f8f3e3368ac56fbecf02fb41b8f8559303f24c5015e", - "sha256:65aacf95b62272d568044531e41de26285d54aec8cb859031f511f84bd8b495a", - "sha256:6758baae2ed64f2331d4fd19be38b7b4eae3ecec210049a26b6a4f3ae1c85dcc", - "sha256:6d1ce5ed2aefcdce11904fc5bbea7d9c21fff3d5f543841edf3dea84451a09ea", - "sha256:6d9f07a80deab4bb0b82858a9e9ad53d1382fd122be8cde11080f4e7dfedb38b", - "sha256:7741f26a58a240f43bee74965c4882b6c93df3e7eb3de160126d8c8f53a6ae6e", - "sha256:8912ef7c2362f7193b5819d17dae8629b34a95c58603d781329712ada83f9447", - "sha256:909645cce2dc28b735674ce0931a4ac94e12f5b13f6bb0b5a5e65e7cea2c192b", - "sha256:96ab43906269ca64a6366934106fa01534454a69e471b7bf3d79083981aaab92", - "sha256:9d78bbc0cbc891ad55b4f39a48c22182e9bdaea7fc0e5dbd364f49f729ca1bbb", - "sha256:ab68d50c06938ef28681073327795c5db99bb4666214d2d5f880ed11aeaded66", - "sha256:ac43031375a65c3196bee99f6001e7fa5bdfb00ddf43379d3c0609bdca042df9", - "sha256:ae82a14dab96fbfad7965403c643cafe6515e386de723e498cf3eeb1e0b70cc7", - "sha256:b2696efdc08648536efd4e1601b5fd491fd47f4db97a5fbfd175549a7365c1b2", - "sha256:b82c5045cebcecd8496a4d694d43f9cc84aeeb49fe2133e036b207abe73f4d30", - "sha256:be0fc24a5e4531ae4d8e858a1a548c1fe33b176bb13eff7f9d0d38ce5112a27d", - "sha256:bf81de2926c2db243c9b2cbc3917619a0fc85796c6ba4e58f541df814bbf83c7", - "sha256:c375cc72229614632c87355366bdf2570c2dac01ac66b8ad048d2dabadf2d0d4", - "sha256:c797dac8bb9c7a3fd3382b16fe8f215b4cf0f22adccea36f1545a6d7be310b41", - "sha256:cef2a73d06601437be399908cf13aee74e86932a5ccc6ccdf173408ebc5f6bb2", - "sha256:d52a3b618cb1cbb769ce2ee1dcdb333c3ab6e823944e9a2d36e37253815f9556", - "sha256:d719465db13267bcef19ea8954a971db03b9f48b4647e3860e4bc8e6ed86610f", - "sha256:d8dd059447824eec055e829258ab092b56bb0579fc3164fa09c64f3acd478772", - "sha256:dbe196377a8248972f5cede786d4c5508ed5f5ca4a1e09b44bda889958b33f8c", - "sha256:e0830e188029c14e891fadd99702fd90d317df294c3298aad682739c5533721a", - "sha256:f053c40f94bc51bc03832a41b4f153d83f2062d88c72b5e79997072594e97e51", - "sha256:f32c7410c7f246838a77d6d1eff0c0f87f3cb0e7c4247aebea71a6d5a68cab49", - "sha256:f6ee45bc4245533111ced13f1f2cace1e7f89d1c793390392a80c139d6cf0e6c", - "sha256:f7c0410f181a531ec4e93bbc27692f2c71a15c2da16766f5ba9761e7ae518413" - ], - "index": "pypi", "markers": "python_version >= '3.9'", - "version": "==3.9.2" + "version": "==3.0.1" }, "minio": { "hashes": [ - "sha256:aa3b485788b63b12406a5798465d12a57e4be2ac2a58a8380959b6b748e64ddd", - "sha256:f8af2dafc22ebe1aef3ac181b8e217037011c430aa6da276ed627e55aaf7c815" + "sha256:a83c2fcd981944602a8dc11e8e07543ed9cda0a9462264e3f46a13171c56bccb", + "sha256:fe5523d9c4a4d6cfc07e96905852841bccdb22b22770e1efca4bf5ae8b65774b" ], "index": "pypi", "markers": "python_version >= '3.9'", - "version": "==7.2.8" + "version": "==7.2.9" }, "mistune": { "hashes": [ @@ -1205,300 +858,172 @@ "markers": "python_version >= '3.7'", "version": "==3.0.2" }, - "mpmath": { - "hashes": [ - "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f", - "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c" - ], - "version": "==1.3.0" - }, "multidict": { "hashes": [ - "sha256:01265f5e40f5a17f8241d52656ed27192be03bfa8764d88e8220141d1e4b3556", - "sha256:0275e35209c27a3f7951e1ce7aaf93ce0d163b28948444bec61dd7badc6d3f8c", - "sha256:04bde7a7b3de05732a4eb39c94574db1ec99abb56162d6c520ad26f83267de29", - "sha256:04da1bb8c8dbadf2a18a452639771951c662c5ad03aefe4884775454be322c9b", - "sha256:09a892e4a9fb47331da06948690ae38eaa2426de97b4ccbfafbdcbe5c8f37ff8", - "sha256:0d63c74e3d7ab26de115c49bffc92cc77ed23395303d496eae515d4204a625e7", - "sha256:107c0cdefe028703fb5dafe640a409cb146d44a6ae201e55b35a4af8e95457dd", - "sha256:141b43360bfd3bdd75f15ed811850763555a251e38b2405967f8e25fb43f7d40", - "sha256:14c2976aa9038c2629efa2c148022ed5eb4cb939e15ec7aace7ca932f48f9ba6", - "sha256:19fe01cea168585ba0f678cad6f58133db2aa14eccaf22f88e4a6dccadfad8b3", - "sha256:1d147090048129ce3c453f0292e7697d333db95e52616b3793922945804a433c", - "sha256:1d9ea7a7e779d7a3561aade7d596649fbecfa5c08a7674b11b423783217933f9", - "sha256:215ed703caf15f578dca76ee6f6b21b7603791ae090fbf1ef9d865571039ade5", - "sha256:21fd81c4ebdb4f214161be351eb5bcf385426bf023041da2fd9e60681f3cebae", - "sha256:220dd781e3f7af2c2c1053da9fa96d9cf3072ca58f057f4c5adaaa1cab8fc442", - "sha256:228b644ae063c10e7f324ab1ab6b548bdf6f8b47f3ec234fef1093bc2735e5f9", - "sha256:29bfeb0dff5cb5fdab2023a7a9947b3b4af63e9c47cae2a10ad58394b517fddc", - "sha256:2f4848aa3baa109e6ab81fe2006c77ed4d3cd1e0ac2c1fbddb7b1277c168788c", - "sha256:2faa5ae9376faba05f630d7e5e6be05be22913782b927b19d12b8145968a85ea", - "sha256:2ffc42c922dbfddb4a4c3b438eb056828719f07608af27d163191cb3e3aa6cc5", - "sha256:37b15024f864916b4951adb95d3a80c9431299080341ab9544ed148091b53f50", - "sha256:3cc2ad10255f903656017363cd59436f2111443a76f996584d1077e43ee51182", - "sha256:3d25f19500588cbc47dc19081d78131c32637c25804df8414463ec908631e453", - "sha256:403c0911cd5d5791605808b942c88a8155c2592e05332d2bf78f18697a5fa15e", - "sha256:411bf8515f3be9813d06004cac41ccf7d1cd46dfe233705933dd163b60e37600", - "sha256:425bf820055005bfc8aa9a0b99ccb52cc2f4070153e34b701acc98d201693733", - "sha256:435a0984199d81ca178b9ae2c26ec3d49692d20ee29bc4c11a2a8d4514c67eda", - "sha256:4a6a4f196f08c58c59e0b8ef8ec441d12aee4125a7d4f4fef000ccb22f8d7241", - "sha256:4cc0ef8b962ac7a5e62b9e826bd0cd5040e7d401bc45a6835910ed699037a461", - "sha256:51d035609b86722963404f711db441cf7134f1889107fb171a970c9701f92e1e", - "sha256:53689bb4e102200a4fafa9de9c7c3c212ab40a7ab2c8e474491914d2305f187e", - "sha256:55205d03e8a598cfc688c71ca8ea5f66447164efff8869517f175ea632c7cb7b", - "sha256:5c0631926c4f58e9a5ccce555ad7747d9a9f8b10619621f22f9635f069f6233e", - "sha256:5cb241881eefd96b46f89b1a056187ea8e9ba14ab88ba632e68d7a2ecb7aadf7", - "sha256:60d698e8179a42ec85172d12f50b1668254628425a6bd611aba022257cac1386", - "sha256:612d1156111ae11d14afaf3a0669ebf6c170dbb735e510a7438ffe2369a847fd", - "sha256:6214c5a5571802c33f80e6c84713b2c79e024995b9c5897f794b43e714daeec9", - "sha256:6939c95381e003f54cd4c5516740faba40cf5ad3eeff460c3ad1d3e0ea2549bf", - "sha256:69db76c09796b313331bb7048229e3bee7928eb62bab5e071e9f7fcc4879caee", - "sha256:6bf7a982604375a8d49b6cc1b781c1747f243d91b81035a9b43a2126c04766f5", - "sha256:766c8f7511df26d9f11cd3a8be623e59cca73d44643abab3f8c8c07620524e4a", - "sha256:76c0de87358b192de7ea9649beb392f107dcad9ad27276324c24c91774ca5271", - "sha256:76f067f5121dcecf0d63a67f29080b26c43c71a98b10c701b0677e4a065fbd54", - "sha256:7901c05ead4b3fb75113fb1dd33eb1253c6d3ee37ce93305acd9d38e0b5f21a4", - "sha256:79660376075cfd4b2c80f295528aa6beb2058fd289f4c9252f986751a4cd0496", - "sha256:79a6d2ba910adb2cbafc95dad936f8b9386e77c84c35bc0add315b856d7c3abb", - "sha256:7afcdd1fc07befad18ec4523a782cde4e93e0a2bf71239894b8d61ee578c1319", - "sha256:7be7047bd08accdb7487737631d25735c9a04327911de89ff1b26b81745bd4e3", - "sha256:7c6390cf87ff6234643428991b7359b5f59cc15155695deb4eda5c777d2b880f", - "sha256:7df704ca8cf4a073334e0427ae2345323613e4df18cc224f647f251e5e75a527", - "sha256:85f67aed7bb647f93e7520633d8f51d3cbc6ab96957c71272b286b2f30dc70ed", - "sha256:896ebdcf62683551312c30e20614305f53125750803b614e9e6ce74a96232604", - "sha256:92d16a3e275e38293623ebf639c471d3e03bb20b8ebb845237e0d3664914caef", - "sha256:99f60d34c048c5c2fabc766108c103612344c46e35d4ed9ae0673d33c8fb26e8", - "sha256:9fe7b0653ba3d9d65cbe7698cca585bf0f8c83dbbcc710db9c90f478e175f2d5", - "sha256:a3145cb08d8625b2d3fee1b2d596a8766352979c9bffe5d7833e0503d0f0b5e5", - "sha256:aeaf541ddbad8311a87dd695ed9642401131ea39ad7bc8cf3ef3967fd093b626", - "sha256:b55358304d7a73d7bdf5de62494aaf70bd33015831ffd98bc498b433dfe5b10c", - "sha256:b82cc8ace10ab5bd93235dfaab2021c70637005e1ac787031f4d1da63d493c1d", - "sha256:c0868d64af83169e4d4152ec612637a543f7a336e4a307b119e98042e852ad9c", - "sha256:c1c1496e73051918fcd4f58ff2e0f2f3066d1c76a0c6aeffd9b45d53243702cc", - "sha256:c9bf56195c6bbd293340ea82eafd0071cb3d450c703d2c93afb89f93b8386ccc", - "sha256:cbebcd5bcaf1eaf302617c114aa67569dd3f090dd0ce8ba9e35e9985b41ac35b", - "sha256:cd6c8fca38178e12c00418de737aef1261576bd1b6e8c6134d3e729a4e858b38", - "sha256:ceb3b7e6a0135e092de86110c5a74e46bda4bd4fbfeeb3a3bcec79c0f861e450", - "sha256:cf590b134eb70629e350691ecca88eac3e3b8b3c86992042fb82e3cb1830d5e1", - "sha256:d3eb1ceec286eba8220c26f3b0096cf189aea7057b6e7b7a2e60ed36b373b77f", - "sha256:d65f25da8e248202bd47445cec78e0025c0fe7582b23ec69c3b27a640dd7a8e3", - "sha256:d6f6d4f185481c9669b9447bf9d9cf3b95a0e9df9d169bbc17e363b7d5487755", - "sha256:d84a5c3a5f7ce6db1f999fb9438f686bc2e09d38143f2d93d8406ed2dd6b9226", - "sha256:d946b0a9eb8aaa590df1fe082cee553ceab173e6cb5b03239716338629c50c7a", - "sha256:dce1c6912ab9ff5f179eaf6efe7365c1f425ed690b03341911bf4939ef2f3046", - "sha256:de170c7b4fe6859beb8926e84f7d7d6c693dfe8e27372ce3b76f01c46e489fcf", - "sha256:e02021f87a5b6932fa6ce916ca004c4d441509d33bbdbeca70d05dff5e9d2479", - "sha256:e030047e85cbcedbfc073f71836d62dd5dadfbe7531cae27789ff66bc551bd5e", - "sha256:e0e79d91e71b9867c73323a3444724d496c037e578a0e1755ae159ba14f4f3d1", - "sha256:e4428b29611e989719874670fd152b6625500ad6c686d464e99f5aaeeaca175a", - "sha256:e4972624066095e52b569e02b5ca97dbd7a7ddd4294bf4e7247d52635630dd83", - "sha256:e7be68734bd8c9a513f2b0cfd508802d6609da068f40dc57d4e3494cefc92929", - "sha256:e8e94e6912639a02ce173341ff62cc1201232ab86b8a8fcc05572741a5dc7d93", - "sha256:ea1456df2a27c73ce51120fa2f519f1bea2f4a03a917f4a43c8707cf4cbbae1a", - "sha256:ebd8d160f91a764652d3e51ce0d2956b38efe37c9231cd82cfc0bed2e40b581c", - "sha256:eca2e9d0cc5a889850e9bbd68e98314ada174ff6ccd1129500103df7a94a7a44", - "sha256:edd08e6f2f1a390bf137080507e44ccc086353c8e98c657e666c017718561b89", - "sha256:f285e862d2f153a70586579c15c44656f888806ed0e5b56b64489afe4a2dbfba", - "sha256:f2a1dee728b52b33eebff5072817176c172050d44d67befd681609b4746e1c2e", - "sha256:f7e301075edaf50500f0b341543c41194d8df3ae5caf4702f2095f3ca73dd8da", - "sha256:fb616be3538599e797a2017cccca78e354c767165e8858ab5116813146041a24", - "sha256:fce28b3c8a81b6b36dfac9feb1de115bab619b3c13905b419ec71d03a3fc1423", - "sha256:fe5d7785250541f7f5019ab9cba2c71169dc7d74d0f45253f8313f436458a4ef" - ], - "markers": "python_version >= '3.7'", - "version": "==6.0.5" - }, - "multiprocess": { - "hashes": [ - "sha256:0dfd078c306e08d46d7a8d06fb120313d87aa43af60d66da43ffff40b44d2f41", - "sha256:161af703d4652a0e1410be6abccecde4a7ddffd19341be0a7011b94aeb171ac1", - "sha256:37b55f71c07e2d741374998c043b9520b626a8dddc8b3129222ca4f1a06ef67a", - "sha256:476887be10e2f59ff183c006af746cb6f1fd0eadcfd4ef49e605cbe2659920ee", - "sha256:a0bafd3ae1b732eac64be2e72038231c1ba97724b60b09400d68f229fcc2fbf3", - "sha256:a71d82033454891091a226dfc319d0cfa8019a4e888ef9ca910372a446de4435", - "sha256:af4cabb0dac72abfb1e794fa7855c325fd2b55a10a44628a3c1ad3311c04127a", - "sha256:ba8c31889abf4511c7308a8c52bb4a30b9d590e7f58523302ba00237702ca054", - "sha256:c4a9944c67bd49f823687463660a2d6daae94c289adff97e0f9d696ba6371d02", - "sha256:d951bed82c8f73929ac82c61f01a7b5ce8f3e5ef40f5b52553b4f547ce2b08ec", - "sha256:e7b9d0f307cd9bd50851afaac0dba2cb6c44449efff697df7c7645f7d3f2be3a", - "sha256:fc0544c531920dde3b00c29863377f87e1632601092ea2daca74e4beb40faa2e" - ], - "markers": "python_version >= '3.8'", - "version": "==0.70.16" - }, - "networkx": { - "hashes": [ - "sha256:0c127d8b2f4865f59ae9cb8aafcd60b5c70f3241ebd66f7defad7c4ab90126c9", - "sha256:28575580c6ebdaf4505b22c6256a2b9de86b316dc63ba9e93abde3d78dfdbcf2" + "sha256:052e10d2d37810b99cc170b785945421141bf7bb7d2f8799d431e7db229c385f", + "sha256:06809f4f0f7ab7ea2cabf9caca7d79c22c0758b58a71f9d32943ae13c7ace056", + "sha256:071120490b47aa997cca00666923a83f02c7fbb44f71cf7f136df753f7fa8761", + "sha256:0c3f390dc53279cbc8ba976e5f8035eab997829066756d811616b652b00a23a3", + "sha256:0e2b90b43e696f25c62656389d32236e049568b39320e2735d51f08fd362761b", + "sha256:0e5f362e895bc5b9e67fe6e4ded2492d8124bdf817827f33c5b46c2fe3ffaca6", + "sha256:10524ebd769727ac77ef2278390fb0068d83f3acb7773792a5080f2b0abf7748", + "sha256:10a9b09aba0c5b48c53761b7c720aaaf7cf236d5fe394cd399c7ba662d5f9966", + "sha256:16e5f4bf4e603eb1fdd5d8180f1a25f30056f22e55ce51fb3d6ad4ab29f7d96f", + "sha256:188215fc0aafb8e03341995e7c4797860181562380f81ed0a87ff455b70bf1f1", + "sha256:189f652a87e876098bbc67b4da1049afb5f5dfbaa310dd67c594b01c10388db6", + "sha256:1ca0083e80e791cffc6efce7660ad24af66c8d4079d2a750b29001b53ff59ada", + "sha256:1e16bf3e5fc9f44632affb159d30a437bfe286ce9e02754759be5536b169b305", + "sha256:2090f6a85cafc5b2db085124d752757c9d251548cedabe9bd31afe6363e0aff2", + "sha256:20b9b5fbe0b88d0bdef2012ef7dee867f874b72528cf1d08f1d59b0e3850129d", + "sha256:22ae2ebf9b0c69d206c003e2f6a914ea33f0a932d4aa16f236afc049d9958f4a", + "sha256:22f3105d4fb15c8f57ff3959a58fcab6ce36814486500cd7485651230ad4d4ef", + "sha256:23bfd518810af7de1116313ebd9092cb9aa629beb12f6ed631ad53356ed6b86c", + "sha256:27e5fc84ccef8dfaabb09d82b7d179c7cf1a3fbc8a966f8274fcb4ab2eb4cadb", + "sha256:3380252550e372e8511d49481bd836264c009adb826b23fefcc5dd3c69692f60", + "sha256:3702ea6872c5a2a4eeefa6ffd36b042e9773f05b1f37ae3ef7264b1163c2dcf6", + "sha256:37bb93b2178e02b7b618893990941900fd25b6b9ac0fa49931a40aecdf083fe4", + "sha256:3914f5aaa0f36d5d60e8ece6a308ee1c9784cd75ec8151062614657a114c4478", + "sha256:3a37ffb35399029b45c6cc33640a92bef403c9fd388acce75cdc88f58bd19a81", + "sha256:3c8b88a2ccf5493b6c8da9076fb151ba106960a2df90c2633f342f120751a9e7", + "sha256:3e97b5e938051226dc025ec80980c285b053ffb1e25a3db2a3aa3bc046bf7f56", + "sha256:3ec660d19bbc671e3a6443325f07263be452c453ac9e512f5eb935e7d4ac28b3", + "sha256:3efe2c2cb5763f2f1b275ad2bf7a287d3f7ebbef35648a9726e3b69284a4f3d6", + "sha256:483a6aea59cb89904e1ceabd2b47368b5600fb7de78a6e4a2c2987b2d256cf30", + "sha256:4867cafcbc6585e4b678876c489b9273b13e9fff9f6d6d66add5e15d11d926cb", + "sha256:48e171e52d1c4d33888e529b999e5900356b9ae588c2f09a52dcefb158b27506", + "sha256:4a9cb68166a34117d6646c0023c7b759bf197bee5ad4272f420a0141d7eb03a0", + "sha256:4b820514bfc0b98a30e3d85462084779900347e4d49267f747ff54060cc33925", + "sha256:4e18b656c5e844539d506a0a06432274d7bd52a7487e6828c63a63d69185626c", + "sha256:4e9f48f58c2c523d5a06faea47866cd35b32655c46b443f163d08c6d0ddb17d6", + "sha256:50b3a2710631848991d0bf7de077502e8994c804bb805aeb2925a981de58ec2e", + "sha256:55b6d90641869892caa9ca42ff913f7ff1c5ece06474fbd32fb2cf6834726c95", + "sha256:57feec87371dbb3520da6192213c7d6fc892d5589a93db548331954de8248fd2", + "sha256:58130ecf8f7b8112cdb841486404f1282b9c86ccb30d3519faf301b2e5659133", + "sha256:5845c1fd4866bb5dd3125d89b90e57ed3138241540897de748cdf19de8a2fca2", + "sha256:59bfeae4b25ec05b34f1956eaa1cb38032282cd4dfabc5056d0a1ec4d696d3aa", + "sha256:5b48204e8d955c47c55b72779802b219a39acc3ee3d0116d5080c388970b76e3", + "sha256:5c09fcfdccdd0b57867577b719c69e347a436b86cd83747f179dbf0cc0d4c1f3", + "sha256:6180c0ae073bddeb5a97a38c03f30c233e0a4d39cd86166251617d1bbd0af436", + "sha256:682b987361e5fd7a139ed565e30d81fd81e9629acc7d925a205366877d8c8657", + "sha256:6b5d83030255983181005e6cfbac1617ce9746b219bc2aad52201ad121226581", + "sha256:6bb5992037f7a9eff7991ebe4273ea7f51f1c1c511e6a2ce511d0e7bdb754492", + "sha256:73eae06aa53af2ea5270cc066dcaf02cc60d2994bbb2c4ef5764949257d10f43", + "sha256:76f364861c3bfc98cbbcbd402d83454ed9e01a5224bb3a28bf70002a230f73e2", + "sha256:820c661588bd01a0aa62a1283f20d2be4281b086f80dad9e955e690c75fb54a2", + "sha256:82176036e65644a6cc5bd619f65f6f19781e8ec2e5330f51aa9ada7504cc1926", + "sha256:87701f25a2352e5bf7454caa64757642734da9f6b11384c1f9d1a8e699758057", + "sha256:9079dfc6a70abe341f521f78405b8949f96db48da98aeb43f9907f342f627cdc", + "sha256:90f8717cb649eea3504091e640a1b8568faad18bd4b9fcd692853a04475a4b80", + "sha256:957cf8e4b6e123a9eea554fa7ebc85674674b713551de587eb318a2df3e00255", + "sha256:99f826cbf970077383d7de805c0681799491cb939c25450b9b5b3ced03ca99f1", + "sha256:9f636b730f7e8cb19feb87094949ba54ee5357440b9658b2a32a5ce4bce53972", + "sha256:a114d03b938376557927ab23f1e950827c3b893ccb94b62fd95d430fd0e5cf53", + "sha256:a185f876e69897a6f3325c3f19f26a297fa058c5e456bfcff8015e9a27e83ae1", + "sha256:a7a9541cd308eed5e30318430a9c74d2132e9a8cb46b901326272d780bf2d423", + "sha256:aa466da5b15ccea564bdab9c89175c762bc12825f4659c11227f515cee76fa4a", + "sha256:aaed8b0562be4a0876ee3b6946f6869b7bcdb571a5d1496683505944e268b160", + "sha256:ab7c4ceb38d91570a650dba194e1ca87c2b543488fe9309b4212694174fd539c", + "sha256:ac10f4c2b9e770c4e393876e35a7046879d195cd123b4f116d299d442b335bcd", + "sha256:b04772ed465fa3cc947db808fa306d79b43e896beb677a56fb2347ca1a49c1fa", + "sha256:b1c416351ee6271b2f49b56ad7f308072f6f44b37118d69c2cad94f3fa8a40d5", + "sha256:b225d95519a5bf73860323e633a664b0d85ad3d5bede6d30d95b35d4dfe8805b", + "sha256:b2f59caeaf7632cc633b5cf6fc449372b83bbdf0da4ae04d5be36118e46cc0aa", + "sha256:b58c621844d55e71c1b7f7c498ce5aa6985d743a1a59034c57a905b3f153c1ef", + "sha256:bf6bea52ec97e95560af5ae576bdac3aa3aae0b6758c6efa115236d9e07dae44", + "sha256:c08be4f460903e5a9d0f76818db3250f12e9c344e79314d1d570fc69d7f4eae4", + "sha256:c7053d3b0353a8b9de430a4f4b4268ac9a4fb3481af37dfe49825bf45ca24156", + "sha256:c943a53e9186688b45b323602298ab727d8865d8c9ee0b17f8d62d14b56f0753", + "sha256:ce2186a7df133a9c895dea3331ddc5ddad42cdd0d1ea2f0a51e5d161e4762f28", + "sha256:d093be959277cb7dee84b801eb1af388b6ad3ca6a6b6bf1ed7585895789d027d", + "sha256:d094ddec350a2fb899fec68d8353c78233debde9b7d8b4beeafa70825f1c281a", + "sha256:d1a9dd711d0877a1ece3d2e4fea11a8e75741ca21954c919406b44e7cf971304", + "sha256:d569388c381b24671589335a3be6e1d45546c2988c2ebe30fdcada8457a31008", + "sha256:d618649d4e70ac6efcbba75be98b26ef5078faad23592f9b51ca492953012429", + "sha256:d83a047959d38a7ff552ff94be767b7fd79b831ad1cd9920662db05fec24fe72", + "sha256:d8fff389528cad1618fb4b26b95550327495462cd745d879a8c7c2115248e399", + "sha256:da1758c76f50c39a2efd5e9859ce7d776317eb1dd34317c8152ac9251fc574a3", + "sha256:db7457bac39421addd0c8449933ac32d8042aae84a14911a757ae6ca3eef1392", + "sha256:e27bbb6d14416713a8bd7aaa1313c0fc8d44ee48d74497a0ff4c3a1b6ccb5167", + "sha256:e617fb6b0b6953fffd762669610c1c4ffd05632c138d61ac7e14ad187870669c", + "sha256:e9aa71e15d9d9beaad2c6b9319edcdc0a49a43ef5c0a4c8265ca9ee7d6c67774", + "sha256:ec2abea24d98246b94913b76a125e855eb5c434f7c46546046372fe60f666351", + "sha256:f179dee3b863ab1c59580ff60f9d99f632f34ccb38bf67a33ec6b3ecadd0fd76", + "sha256:f4c035da3f544b1882bac24115f3e2e8760f10a0107614fc9839fd232200b875", + "sha256:f67f217af4b1ff66c68a87318012de788dd95fcfeb24cc889011f4e1c7454dfd", + "sha256:f90c822a402cb865e396a504f9fc8173ef34212a342d92e362ca498cad308e28", + "sha256:ff3827aef427c89a25cc96ded1759271a93603aba9fb977a6d264648ebf989db" ], - "markers": "python_version >= '3.10'", - "version": "==3.3" - }, - "nltk": { - "hashes": [ - "sha256:4fa26829c5b00715afe3061398a8989dc643b92ce7dd93fb4585a70930d168a1", - "sha256:87d127bd3de4bd89a4f81265e5fa59cb1b199b27440175370f7417d2bc7ae868" - ], - "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==3.9.1" + "version": "==6.1.0" }, "numpy": { "hashes": [ - "sha256:03a8c78d01d9781b28a6989f6fa1bb2c4f2d51201cf99d3dd875df6fbd96b23b", - "sha256:08beddf13648eb95f8d867350f6a018a4be2e5ad54c8d8caed89ebca558b2818", - "sha256:1af303d6b2210eb850fcf03064d364652b7120803a0b872f5211f5234b399f20", - "sha256:1dda2e7b4ec9dd512f84935c5f126c8bd8b9f2fc001e9f54af255e8c5f16b0e0", - "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010", - "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a", - "sha256:3373d5d70a5fe74a2c1bb6d2cfd9609ecf686d47a2d7b1d37a8f3b6bf6003aea", - "sha256:47711010ad8555514b434df65f7d7b076bb8261df1ca9bb78f53d3b2db02e95c", - "sha256:4c66707fabe114439db9068ee468c26bbdf909cac0fb58686a42a24de1760c71", - "sha256:50193e430acfc1346175fcbdaa28ffec49947a06918b7b92130744e81e640110", - "sha256:52b8b60467cd7dd1e9ed082188b4e6bb35aa5cdd01777621a1658910745b90be", - "sha256:60dedbb91afcbfdc9bc0b1f3f402804070deed7392c23eb7a7f07fa857868e8a", - "sha256:62b8e4b1e28009ef2846b4c7852046736bab361f7aeadeb6a5b89ebec3c7055a", - "sha256:666dbfb6ec68962c033a450943ded891bed2d54e6755e35e5835d63f4f6931d5", - "sha256:675d61ffbfa78604709862923189bad94014bef562cc35cf61d3a07bba02a7ed", - "sha256:679b0076f67ecc0138fd2ede3a8fd196dddc2ad3254069bcb9faf9a79b1cebcd", - "sha256:7349ab0fa0c429c82442a27a9673fc802ffdb7c7775fad780226cb234965e53c", - "sha256:7ab55401287bfec946ced39700c053796e7cc0e3acbef09993a9ad2adba6ca6e", - "sha256:7e50d0a0cc3189f9cb0aeb3a6a6af18c16f59f004b866cd2be1c14b36134a4a0", - "sha256:95a7476c59002f2f6c590b9b7b998306fba6a5aa646b1e22ddfeaf8f78c3a29c", - "sha256:96ff0b2ad353d8f990b63294c8986f1ec3cb19d749234014f4e7eb0112ceba5a", - "sha256:9fad7dcb1aac3c7f0584a5a8133e3a43eeb2fe127f47e3632d43d677c66c102b", - "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0", - "sha256:a354325ee03388678242a4d7ebcd08b5c727033fcff3b2f536aea978e15ee9e6", - "sha256:a4abb4f9001ad2858e7ac189089c42178fcce737e4169dc61321660f1a96c7d2", - "sha256:ab47dbe5cc8210f55aa58e4805fe224dac469cde56b9f731a4c098b91917159a", - "sha256:afedb719a9dcfc7eaf2287b839d8198e06dcd4cb5d276a3df279231138e83d30", - "sha256:b3ce300f3644fb06443ee2222c2201dd3a89ea6040541412b8fa189341847218", - "sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5", - "sha256:bfe25acf8b437eb2a8b2d49d443800a5f18508cd811fea3181723922a8a82b07", - "sha256:cd25bcecc4974d09257ffcd1f098ee778f7834c3ad767fe5db785be9a4aa9cb2", - "sha256:d209d8969599b27ad20994c8e41936ee0964e6da07478d6c35016bc386b66ad4", - "sha256:d5241e0a80d808d70546c697135da2c613f30e28251ff8307eb72ba696945764", - "sha256:edd8b5fe47dab091176d21bb6de568acdd906d1887a4584a15a9a96a1dca06ef", - "sha256:f870204a840a60da0b12273ef34f7051e98c3b5961b61b0c2c1be6dfd64fbcd3", - "sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f" + "sha256:05b2d4e667895cc55e3ff2b56077e4c8a5604361fc21a042845ea3ad67465aa8", + "sha256:12edb90831ff481f7ef5f6bc6431a9d74dc0e5ff401559a71e5e4611d4f2d466", + "sha256:13311c2db4c5f7609b462bc0f43d3c465424d25c626d95040f073e30f7570e35", + "sha256:13532a088217fa624c99b843eeb54640de23b3414b14aa66d023805eb731066c", + "sha256:13602b3174432a35b16c4cfb5de9a12d229727c3dd47a6ce35111f2ebdf66ff4", + "sha256:1600068c262af1ca9580a527d43dc9d959b0b1d8e56f8a05d830eea39b7c8af6", + "sha256:1b8cde4f11f0a975d1fd59373b32e2f5a562ade7cde4f85b7137f3de8fbb29a0", + "sha256:1c193d0b0238638e6fc5f10f1b074a6993cb13b0b431f64079a509d63d3aa8b7", + "sha256:1ebec5fd716c5a5b3d8dfcc439be82a8407b7b24b230d0ad28a81b61c2f4659a", + "sha256:242b39d00e4944431a3cd2db2f5377e15b5785920421993770cddb89992c3f3a", + "sha256:259ec80d54999cc34cd1eb8ded513cb053c3bf4829152a2e00de2371bd406f5e", + "sha256:2abbf905a0b568706391ec6fa15161fad0fb5d8b68d73c461b3c1bab6064dd62", + "sha256:2cbba4b30bf31ddbe97f1c7205ef976909a93a66bb1583e983adbd155ba72ac2", + "sha256:2ffef621c14ebb0188a8633348504a35c13680d6da93ab5cb86f4e54b7e922b5", + "sha256:30d53720b726ec36a7f88dc873f0eec8447fbc93d93a8f079dfac2629598d6ee", + "sha256:32e16a03138cabe0cb28e1007ee82264296ac0983714094380b408097a418cfe", + "sha256:43cca367bf94a14aca50b89e9bc2061683116cfe864e56740e083392f533ce7a", + "sha256:456e3b11cb79ac9946c822a56346ec80275eaf2950314b249b512896c0d2505e", + "sha256:4d6ec0d4222e8ffdab1744da2560f07856421b367928026fb540e1945f2eeeaf", + "sha256:5006b13a06e0b38d561fab5ccc37581f23c9511879be7693bd33c7cd15ca227c", + "sha256:675c741d4739af2dc20cd6c6a5c4b7355c728167845e3c6b0e824e4e5d36a6c3", + "sha256:6cdb606a7478f9ad91c6283e238544451e3a95f30fb5467fbf715964341a8a86", + "sha256:6d95f286b8244b3649b477ac066c6906fbb2905f8ac19b170e2175d3d799f4df", + "sha256:76322dcdb16fccf2ac56f99048af32259dcc488d9b7e25b51e5eca5147a3fb98", + "sha256:7c1c60328bd964b53f8b835df69ae8198659e2b9302ff9ebb7de4e5a5994db3d", + "sha256:860ec6e63e2c5c2ee5e9121808145c7bf86c96cca9ad396c0bd3e0f2798ccbe2", + "sha256:8e00ea6fc82e8a804433d3e9cedaa1051a1422cb6e443011590c14d2dea59146", + "sha256:9c6c754df29ce6a89ed23afb25550d1c2d5fdb9901d9c67a16e0b16eaf7e2550", + "sha256:a26ae94658d3ba3781d5e103ac07a876b3e9b29db53f68ed7df432fd033358a8", + "sha256:a65acfdb9c6ebb8368490dbafe83c03c7e277b37e6857f0caeadbbc56e12f4fb", + "sha256:a7d80b2e904faa63068ead63107189164ca443b42dd1930299e0d1cb041cec2e", + "sha256:a84498e0d0a1174f2b3ed769b67b656aa5460c92c9554039e11f20a05650f00d", + "sha256:ab4754d432e3ac42d33a269c8567413bdb541689b02d93788af4131018cbf366", + "sha256:ad369ed238b1959dfbade9018a740fb9392c5ac4f9b5173f420bd4f37ba1f7a0", + "sha256:b1d0fcae4f0949f215d4632be684a539859b295e2d0cb14f78ec231915d644db", + "sha256:b42a1a511c81cc78cbc4539675713bbcf9d9c3913386243ceff0e9429ca892fe", + "sha256:bd33f82e95ba7ad632bc57837ee99dba3d7e006536200c4e9124089e1bf42426", + "sha256:bdd407c40483463898b84490770199d5714dcc9dd9b792f6c6caccc523c00952", + "sha256:c6eef7a2dbd0abfb0d9eaf78b73017dbfd0b54051102ff4e6a7b2980d5ac1a03", + "sha256:c82af4b2ddd2ee72d1fc0c6695048d457e00b3582ccde72d8a1c991b808bb20f", + "sha256:d666cb72687559689e9906197e3bec7b736764df6a2e58ee265e360663e9baf7", + "sha256:d7bf0a4f9f15b32b5ba53147369e94296f5fffb783db5aacc1be15b4bf72f43b", + "sha256:d82075752f40c0ddf57e6e02673a17f6cb0f8eb3f587f63ca1eaab5594da5b17", + "sha256:da65fb46d4cbb75cb417cddf6ba5e7582eb7bb0b47db4b99c9fe5787ce5d91f5", + "sha256:e2b49c3c0804e8ecb05d59af8386ec2f74877f7ca8fd9c1e00be2672e4d399b1", + "sha256:e585c8ae871fd38ac50598f4763d73ec5497b0de9a0ab4ef5b69f01c6a046142", + "sha256:e8d3ca0a72dd8846eb6f7dfe8f19088060fcb76931ed592d29128e0219652884", + "sha256:ef444c57d664d35cac4e18c298c47d7b504c66b17c2ea91312e979fcfbdfb08a", + "sha256:f1eb068ead09f4994dec71c24b2844f1e4e4e013b9629f812f292f04bd1510d9", + "sha256:f2ded8d9b6f68cc26f8425eda5d3877b47343e68ca23d0d0846f4d312ecaa445", + "sha256:f751ed0a2f250541e19dfca9f1eafa31a392c71c832b6bb9e113b10d050cb0f1", + "sha256:faa88bc527d0f097abdc2c663cddf37c05a1c2f113716601555249805cf573f1", + "sha256:fc44e3c68ff00fd991b59092a54350e6e4911152682b4782f68070985aa9e648" ], "index": "pypi", - "markers": "python_version >= '3.9'", - "version": "==1.26.4" - }, - "nvidia-cublas-cu12": { - "hashes": [ - "sha256:2b964d60e8cf11b5e1073d179d85fa340c120e99b3067558f3cf98dd69d02906", - "sha256:ee53ccca76a6fc08fb9701aa95b6ceb242cdaab118c3bb152af4e579af792728" - ], - "markers": "platform_system == 'Linux' and platform_machine == 'x86_64'", - "version": "==12.1.3.1" - }, - "nvidia-cuda-cupti-cu12": { - "hashes": [ - "sha256:bea8236d13a0ac7190bd2919c3e8e6ce1e402104276e6f9694479e48bb0eb2a4", - "sha256:e54fde3983165c624cb79254ae9818a456eb6e87a7fd4d56a2352c24ee542d7e" - ], - "markers": "platform_system == 'Linux' and platform_machine == 'x86_64'", - "version": "==12.1.105" - }, - "nvidia-cuda-nvrtc-cu12": { - "hashes": [ - "sha256:0a98a522d9ff138b96c010a65e145dc1b4850e9ecb75a0172371793752fd46ed", - "sha256:339b385f50c309763ca65456ec75e17bbefcbbf2893f462cb8b90584cd27a1c2" - ], - "markers": "platform_system == 'Linux' and platform_machine == 'x86_64'", - "version": "==12.1.105" - }, - "nvidia-cuda-runtime-cu12": { - "hashes": [ - "sha256:6e258468ddf5796e25f1dc591a31029fa317d97a0a94ed93468fc86301d61e40", - "sha256:dfb46ef84d73fababab44cf03e3b83f80700d27ca300e537f85f636fac474344" - ], - "markers": "platform_system == 'Linux' and platform_machine == 'x86_64'", - "version": "==12.1.105" - }, - "nvidia-cudnn-cu12": { - "hashes": [ - "sha256:165764f44ef8c61fcdfdfdbe769d687e06374059fbb388b6c89ecb0e28793a6f", - "sha256:6278562929433d68365a07a4a1546c237ba2849852c0d4b2262a486e805b977a" - ], - "markers": "platform_system == 'Linux' and platform_machine == 'x86_64'", - "version": "==9.1.0.70" - }, - "nvidia-cufft-cu12": { - "hashes": [ - "sha256:794e3948a1aa71fd817c3775866943936774d1c14e7628c74f6f7417224cdf56", - "sha256:d9ac353f78ff89951da4af698f80870b1534ed69993f10a4cf1d96f21357e253" - ], - "markers": "platform_system == 'Linux' and platform_machine == 'x86_64'", - "version": "==11.0.2.54" - }, - "nvidia-curand-cu12": { - "hashes": [ - "sha256:75b6b0c574c0037839121317e17fd01f8a69fd2ef8e25853d826fec30bdba74a", - "sha256:9d264c5036dde4e64f1de8c50ae753237c12e0b1348738169cd0f8a536c0e1e0" - ], - "markers": "platform_system == 'Linux' and platform_machine == 'x86_64'", - "version": "==10.3.2.106" - }, - "nvidia-cusolver-cu12": { - "hashes": [ - "sha256:74e0c3a24c78612192a74fcd90dd117f1cf21dea4822e66d89e8ea80e3cd2da5", - "sha256:8a7ec542f0412294b15072fa7dab71d31334014a69f953004ea7a118206fe0dd" - ], - "markers": "platform_system == 'Linux' and platform_machine == 'x86_64'", - "version": "==11.4.5.107" - }, - "nvidia-cusparse-cu12": { - "hashes": [ - "sha256:b798237e81b9719373e8fae8d4f091b70a0cf09d9d85c95a557e11df2d8e9a5a", - "sha256:f3b50f42cf363f86ab21f720998517a659a48131e8d538dc02f8768237bd884c" - ], - "markers": "platform_system == 'Linux' and platform_machine == 'x86_64'", - "version": "==12.1.0.106" - }, - "nvidia-nccl-cu12": { - "hashes": [ - "sha256:057f6bf9685f75215d0c53bf3ac4a10b3e6578351de307abad9e18a99182af56", - "sha256:1fc150d5c3250b170b29410ba682384b14581db722b2531b0d8d33c595f33d01" - ], - "markers": "platform_system == 'Linux' and platform_machine == 'x86_64'", - "version": "==2.20.5" - }, - "nvidia-nvjitlink-cu12": { - "hashes": [ - "sha256:562ab97ea2c23164823b2a89cb328d01d45cb99634b8c65fe7cd60d14562bd79", - "sha256:84fb38465a5bc7c70cbc320cfd0963eb302ee25a5e939e9f512bbba55b6072fb", - "sha256:ed3c43a17f37b0c922a919203d2d36cbef24d41cc3e6b625182f8b58203644f6" - ], - "markers": "python_version >= '3'", - "version": "==12.6.20" - }, - "nvidia-nvtx-cu12": { - "hashes": [ - "sha256:65f4d98982b31b60026e0e6de73fbdfc09d08a96f4656dd3665ca616a11e1e82", - "sha256:dc21cf308ca5691e7c04d962e213f8a4aa9bbfa23d95412f452254c2caeb09e5" - ], - "markers": "platform_system == 'Linux' and platform_machine == 'x86_64'", - "version": "==12.1.105" + "markers": "python_version >= '3.10'", + "version": "==2.1.2" }, "opensearch-py": { "hashes": [ - "sha256:6a36535efcda870c820fd84c4bda96d7d57fc900a8c7dec660a48c079904df97", - "sha256:c09a73727868c29f86ffbed1e987afb7f86bcce983b28bf69249cfad8c831d68" + "sha256:5417650eba98a1c7648e502207cebf3a12beab623ffe0ebbf55f9b1b4b6e44e9", + "sha256:67ab76e9373669bc71da417096df59827c08369ac3795d5438c9a8be21cbd759" ], "index": "pypi", "markers": "python_version >= '3.8' and python_version < '4'", - "version": "==2.7.0" - }, - "owlready2": { - "hashes": [ - "sha256:3c1b06dbe85df77dfa2de5a13ba1d11b4b8543c1c0ccdc5be252a81e3c0de55a" - ], - "index": "pypi", - "markers": "python_version >= '3.6'", - "version": "==0.46" + "version": "==2.7.1" }, "packaging": { "hashes": [ @@ -1510,48 +1035,52 @@ }, "pandas": { "hashes": [ - "sha256:001910ad31abc7bf06f49dcc903755d2f7f3a9186c0c040b827e522e9cef0863", - "sha256:0ca6377b8fca51815f382bd0b697a0814c8bda55115678cbc94c30aacbb6eff2", - "sha256:0cace394b6ea70c01ca1595f839cf193df35d1575986e484ad35c4aeae7266c1", - "sha256:1cb51fe389360f3b5a4d57dbd2848a5f033350336ca3b340d1c53a1fad33bcad", - "sha256:2925720037f06e89af896c70bca73459d7e6a4be96f9de79e2d440bd499fe0db", - "sha256:3e374f59e440d4ab45ca2fffde54b81ac3834cf5ae2cdfa69c90bc03bde04d76", - "sha256:40ae1dffb3967a52203105a077415a86044a2bea011b5f321c6aa64b379a3f51", - "sha256:43498c0bdb43d55cb162cdc8c06fac328ccb5d2eabe3cadeb3529ae6f0517c32", - "sha256:4abfe0be0d7221be4f12552995e58723c7422c80a659da13ca382697de830c08", - "sha256:58b84b91b0b9f4bafac2a0ac55002280c094dfc6402402332c0913a59654ab2b", - "sha256:640cef9aa381b60e296db324337a554aeeb883ead99dc8f6c18e81a93942f5f4", - "sha256:66b479b0bd07204e37583c191535505410daa8df638fd8e75ae1b383851fe921", - "sha256:696039430f7a562b74fa45f540aca068ea85fa34c244d0deee539cb6d70aa288", - "sha256:6d2123dc9ad6a814bcdea0f099885276b31b24f7edf40f6cdbc0912672e22eee", - "sha256:8635c16bf3d99040fdf3ca3db669a7250ddf49c55dc4aa8fe0ae0fa8d6dcc1f0", - "sha256:873d13d177501a28b2756375d59816c365e42ed8417b41665f346289adc68d24", - "sha256:8e5a0b00e1e56a842f922e7fae8ae4077aee4af0acb5ae3622bd4b4c30aedf99", - "sha256:8e90497254aacacbc4ea6ae5e7a8cd75629d6ad2b30025a4a8b09aa4faf55151", - "sha256:9057e6aa78a584bc93a13f0a9bf7e753a5e9770a30b4d758b8d5f2a62a9433cd", - "sha256:90c6fca2acf139569e74e8781709dccb6fe25940488755716d1d354d6bc58bce", - "sha256:92fd6b027924a7e178ac202cfbe25e53368db90d56872d20ffae94b96c7acc57", - "sha256:9dfde2a0ddef507a631dc9dc4af6a9489d5e2e740e226ad426a05cabfbd7c8ef", - "sha256:9e79019aba43cb4fda9e4d983f8e88ca0373adbb697ae9c6c43093218de28b54", - "sha256:a77e9d1c386196879aa5eb712e77461aaee433e54c68cf253053a73b7e49c33a", - "sha256:c7adfc142dac335d8c1e0dcbd37eb8617eac386596eb9e1a1b77791cf2498238", - "sha256:d187d355ecec3629624fccb01d104da7d7f391db0311145817525281e2804d23", - "sha256:ddf818e4e6c7c6f4f7c8a12709696d193976b591cc7dc50588d3d1a6b5dc8772", - "sha256:e9b79011ff7a0f4b1d6da6a61aa1aa604fb312d6647de5bad20013682d1429ce", - "sha256:eee3a87076c0756de40b05c5e9a6069c035ba43e8dd71c379e68cab2c20f16ad" + "sha256:062309c1b9ea12a50e8ce661145c6aab431b1e99530d3cd60640e255778bd43a", + "sha256:15c0e1e02e93116177d29ff83e8b1619c93ddc9c49083f237d4312337a61165d", + "sha256:1948ddde24197a0f7add2bdc4ca83bf2b1ef84a1bc8ccffd95eda17fd836ecb5", + "sha256:1db71525a1538b30142094edb9adc10be3f3e176748cd7acc2240c2f2e5aa3a4", + "sha256:22a9d949bfc9a502d320aa04e5d02feab689d61da4e7764b62c30b991c42c5f0", + "sha256:29401dbfa9ad77319367d36940cd8a0b3a11aba16063e39632d98b0e931ddf32", + "sha256:31d0ced62d4ea3e231a9f228366919a5ea0b07440d9d4dac345376fd8e1477ea", + "sha256:3508d914817e153ad359d7e069d752cdd736a247c322d932eb89e6bc84217f28", + "sha256:37e0aced3e8f539eccf2e099f65cdb9c8aa85109b0be6e93e2baff94264bdc6f", + "sha256:381175499d3802cde0eabbaf6324cce0c4f5d52ca6f8c377c29ad442f50f6348", + "sha256:38cf8125c40dae9d5acc10fa66af8ea6fdf760b2714ee482ca691fc66e6fcb18", + "sha256:3b71f27954685ee685317063bf13c7709a7ba74fc996b84fc6821c59b0f06468", + "sha256:3fc6873a41186404dad67245896a6e440baacc92f5b716ccd1bc9ed2995ab2c5", + "sha256:4850ba03528b6dd51d6c5d273c46f183f39a9baf3f0143e566b89450965b105e", + "sha256:4f18ba62b61d7e192368b84517265a99b4d7ee8912f8708660fb4a366cc82667", + "sha256:56534ce0746a58afaf7942ba4863e0ef81c9c50d3f0ae93e9497d6a41a057645", + "sha256:59ef3764d0fe818125a5097d2ae867ca3fa64df032331b7e0917cf5d7bf66b13", + "sha256:5dbca4c1acd72e8eeef4753eeca07de9b1db4f398669d5994086f788a5d7cc30", + "sha256:5de54125a92bb4d1c051c0659e6fcb75256bf799a732a87184e5ea503965bce3", + "sha256:61c5ad4043f791b61dd4752191d9f07f0ae412515d59ba8f005832a532f8736d", + "sha256:6374c452ff3ec675a8f46fd9ab25c4ad0ba590b71cf0656f8b6daa5202bca3fb", + "sha256:63cc132e40a2e084cf01adf0775b15ac515ba905d7dcca47e9a251819c575ef3", + "sha256:66108071e1b935240e74525006034333f98bcdb87ea116de573a6a0dccb6c039", + "sha256:6dfcb5ee8d4d50c06a51c2fffa6cff6272098ad6540aed1a76d15fb9318194d8", + "sha256:7c2875855b0ff77b2a64a0365e24455d9990730d6431b9e0ee18ad8acee13dbd", + "sha256:7eee9e7cea6adf3e3d24e304ac6b8300646e2a5d1cd3a3c2abed9101b0846761", + "sha256:800250ecdadb6d9c78eae4990da62743b857b470883fa27f652db8bdde7f6659", + "sha256:86976a1c5b25ae3f8ccae3a5306e443569ee3c3faf444dfd0f41cda24667ad57", + "sha256:8cd6d7cc958a3910f934ea8dbdf17b2364827bb4dafc38ce6eef6bb3d65ff09c", + "sha256:99df71520d25fade9db7c1076ac94eb994f4d2673ef2aa2e86ee039b6746d20c", + "sha256:a5a1595fe639f5988ba6a8e5bc9649af3baf26df3998a0abe56c02609392e0a4", + "sha256:ad5b65698ab28ed8d7f18790a0dc58005c7629f227be9ecc1072aa74c0c1d43a", + "sha256:b1d432e8d08679a40e2a6d8b2f9770a5c21793a6f9f47fdd52c5ce1948a5a8a9", + "sha256:b8661b0238a69d7aafe156b7fa86c44b881387509653fdf857bebc5e4008ad42", + "sha256:ba96630bc17c875161df3818780af30e43be9b166ce51c9a18c1feae342906c2", + "sha256:bc6b93f9b966093cb0fd62ff1a7e4c09e6d546ad7c1de191767baffc57628f39", + "sha256:c124333816c3a9b03fbeef3a9f230ba9a737e9e5bb4060aa2107a86cc0a497fc", + "sha256:cd8d0c3be0515c12fed0bdbae072551c8b54b7192c7b1fda0ba56059a0179698", + "sha256:d9c45366def9a3dd85a6454c0e7908f2b3b8e9c138f5dc38fed7ce720d8453ed", + "sha256:f00d1345d84d8c86a63e476bb4955e46458b304b9575dcf71102b5c705320015", + "sha256:f3a255b2c19987fbbe62a9dfd6cff7ff2aa9ccab3fc75218fd4b7530f01efa24", + "sha256:fffb8ae78d8af97f849404f21411c95062db1496aeb3e56f146f0355c9989319" ], "index": "pypi", "markers": "python_version >= '3.9'", - "version": "==2.2.2" - }, - "peft": { - "hashes": [ - "sha256:253205bd478e985ccdc7f04804aab9c95f479130c517bf6e474b8d509db5f4a4", - "sha256:a47915efb08af50e9fda267b7bf1b5b6eff33ccbb08791bdb544dccb8788f674" - ], - "index": "pypi", - "markers": "python_full_version >= '3.8.0'", - "version": "==0.12.0" + "version": "==2.2.3" }, "pika": { "hashes": [ @@ -1561,99 +1090,13 @@ "markers": "python_version >= '3.7'", "version": "==1.3.2" }, - "pillow": { - "hashes": [ - "sha256:02a2be69f9c9b8c1e97cf2713e789d4e398c751ecfd9967c18d0ce304efbf885", - "sha256:030abdbe43ee02e0de642aee345efa443740aa4d828bfe8e2eb11922ea6a21ea", - "sha256:06b2f7898047ae93fad74467ec3d28fe84f7831370e3c258afa533f81ef7f3df", - "sha256:0755ffd4a0c6f267cccbae2e9903d95477ca2f77c4fcf3a3a09570001856c8a5", - "sha256:0a9ec697746f268507404647e531e92889890a087e03681a3606d9b920fbee3c", - "sha256:0ae24a547e8b711ccaaf99c9ae3cd975470e1a30caa80a6aaee9a2f19c05701d", - "sha256:134ace6dc392116566980ee7436477d844520a26a4b1bd4053f6f47d096997fd", - "sha256:166c1cd4d24309b30d61f79f4a9114b7b2313d7450912277855ff5dfd7cd4a06", - "sha256:1b5dea9831a90e9d0721ec417a80d4cbd7022093ac38a568db2dd78363b00908", - "sha256:1d846aea995ad352d4bdcc847535bd56e0fd88d36829d2c90be880ef1ee4668a", - "sha256:1ef61f5dd14c300786318482456481463b9d6b91ebe5ef12f405afbba77ed0be", - "sha256:297e388da6e248c98bc4a02e018966af0c5f92dfacf5a5ca22fa01cb3179bca0", - "sha256:298478fe4f77a4408895605f3482b6cc6222c018b2ce565c2b6b9c354ac3229b", - "sha256:29dbdc4207642ea6aad70fbde1a9338753d33fb23ed6956e706936706f52dd80", - "sha256:2db98790afc70118bd0255c2eeb465e9767ecf1f3c25f9a1abb8ffc8cfd1fe0a", - "sha256:32cda9e3d601a52baccb2856b8ea1fc213c90b340c542dcef77140dfa3278a9e", - "sha256:37fb69d905be665f68f28a8bba3c6d3223c8efe1edf14cc4cfa06c241f8c81d9", - "sha256:416d3a5d0e8cfe4f27f574362435bc9bae57f679a7158e0096ad2beb427b8696", - "sha256:43efea75eb06b95d1631cb784aa40156177bf9dd5b4b03ff38979e048258bc6b", - "sha256:4b35b21b819ac1dbd1233317adeecd63495f6babf21b7b2512d244ff6c6ce309", - "sha256:4d9667937cfa347525b319ae34375c37b9ee6b525440f3ef48542fcf66f2731e", - "sha256:5161eef006d335e46895297f642341111945e2c1c899eb406882a6c61a4357ab", - "sha256:543f3dc61c18dafb755773efc89aae60d06b6596a63914107f75459cf984164d", - "sha256:551d3fd6e9dc15e4c1eb6fc4ba2b39c0c7933fa113b220057a34f4bb3268a060", - "sha256:59291fb29317122398786c2d44427bbd1a6d7ff54017075b22be9d21aa59bd8d", - "sha256:5b001114dd152cfd6b23befeb28d7aee43553e2402c9f159807bf55f33af8a8d", - "sha256:5b4815f2e65b30f5fbae9dfffa8636d992d49705723fe86a3661806e069352d4", - "sha256:5dc6761a6efc781e6a1544206f22c80c3af4c8cf461206d46a1e6006e4429ff3", - "sha256:5e84b6cc6a4a3d76c153a6b19270b3526a5a8ed6b09501d3af891daa2a9de7d6", - "sha256:6209bb41dc692ddfee4942517c19ee81b86c864b626dbfca272ec0f7cff5d9fb", - "sha256:673655af3eadf4df6b5457033f086e90299fdd7a47983a13827acf7459c15d94", - "sha256:6c762a5b0997f5659a5ef2266abc1d8851ad7749ad9a6a5506eb23d314e4f46b", - "sha256:7086cc1d5eebb91ad24ded9f58bec6c688e9f0ed7eb3dbbf1e4800280a896496", - "sha256:73664fe514b34c8f02452ffb73b7a92c6774e39a647087f83d67f010eb9a0cf0", - "sha256:76a911dfe51a36041f2e756b00f96ed84677cdeb75d25c767f296c1c1eda1319", - "sha256:780c072c2e11c9b2c7ca37f9a2ee8ba66f44367ac3e5c7832afcfe5104fd6d1b", - "sha256:7928ecbf1ece13956b95d9cbcfc77137652b02763ba384d9ab508099a2eca856", - "sha256:7970285ab628a3779aecc35823296a7869f889b8329c16ad5a71e4901a3dc4ef", - "sha256:7a8d4bade9952ea9a77d0c3e49cbd8b2890a399422258a77f357b9cc9be8d680", - "sha256:7c1ee6f42250df403c5f103cbd2768a28fe1a0ea1f0f03fe151c8741e1469c8b", - "sha256:7dfecdbad5c301d7b5bde160150b4db4c659cee2b69589705b6f8a0c509d9f42", - "sha256:812f7342b0eee081eaec84d91423d1b4650bb9828eb53d8511bcef8ce5aecf1e", - "sha256:866b6942a92f56300012f5fbac71f2d610312ee65e22f1aa2609e491284e5597", - "sha256:86dcb5a1eb778d8b25659d5e4341269e8590ad6b4e8b44d9f4b07f8d136c414a", - "sha256:87dd88ded2e6d74d31e1e0a99a726a6765cda32d00ba72dc37f0651f306daaa8", - "sha256:8bc1a764ed8c957a2e9cacf97c8b2b053b70307cf2996aafd70e91a082e70df3", - "sha256:8d4d5063501b6dd4024b8ac2f04962d661222d120381272deea52e3fc52d3736", - "sha256:8f0aef4ef59694b12cadee839e2ba6afeab89c0f39a3adc02ed51d109117b8da", - "sha256:930044bb7679ab003b14023138b50181899da3f25de50e9dbee23b61b4de2126", - "sha256:950be4d8ba92aca4b2bb0741285a46bfae3ca699ef913ec8416c1b78eadd64cd", - "sha256:961a7293b2457b405967af9c77dcaa43cc1a8cd50d23c532e62d48ab6cdd56f5", - "sha256:9b885f89040bb8c4a1573566bbb2f44f5c505ef6e74cec7ab9068c900047f04b", - "sha256:9f4727572e2918acaa9077c919cbbeb73bd2b3ebcfe033b72f858fc9fbef0026", - "sha256:a02364621fe369e06200d4a16558e056fe2805d3468350df3aef21e00d26214b", - "sha256:a985e028fc183bf12a77a8bbf36318db4238a3ded7fa9df1b9a133f1cb79f8fc", - "sha256:ac1452d2fbe4978c2eec89fb5a23b8387aba707ac72810d9490118817d9c0b46", - "sha256:b15e02e9bb4c21e39876698abf233c8c579127986f8207200bc8a8f6bb27acf2", - "sha256:b2724fdb354a868ddf9a880cb84d102da914e99119211ef7ecbdc613b8c96b3c", - "sha256:bbc527b519bd3aa9d7f429d152fea69f9ad37c95f0b02aebddff592688998abe", - "sha256:bcd5e41a859bf2e84fdc42f4edb7d9aba0a13d29a2abadccafad99de3feff984", - "sha256:bd2880a07482090a3bcb01f4265f1936a903d70bc740bfcb1fd4e8a2ffe5cf5a", - "sha256:bee197b30783295d2eb680b311af15a20a8b24024a19c3a26431ff83eb8d1f70", - "sha256:bf2342ac639c4cf38799a44950bbc2dfcb685f052b9e262f446482afaf4bffca", - "sha256:c76e5786951e72ed3686e122d14c5d7012f16c8303a674d18cdcd6d89557fc5b", - "sha256:cbed61494057c0f83b83eb3a310f0bf774b09513307c434d4366ed64f4128a91", - "sha256:cfdd747216947628af7b259d274771d84db2268ca062dd5faf373639d00113a3", - "sha256:d7480af14364494365e89d6fddc510a13e5a2c3584cb19ef65415ca57252fb84", - "sha256:dbc6ae66518ab3c5847659e9988c3b60dc94ffb48ef9168656e0019a93dbf8a1", - "sha256:dc3e2db6ba09ffd7d02ae9141cfa0ae23393ee7687248d46a7507b75d610f4f5", - "sha256:dfe91cb65544a1321e631e696759491ae04a2ea11d36715eca01ce07284738be", - "sha256:e4d49b85c4348ea0b31ea63bc75a9f3857869174e2bf17e7aba02945cd218e6f", - "sha256:e4db64794ccdf6cb83a59d73405f63adbe2a1887012e308828596100a0b2f6cc", - "sha256:e553cad5179a66ba15bb18b353a19020e73a7921296a7979c4a2b7f6a5cd57f9", - "sha256:e88d5e6ad0d026fba7bdab8c3f225a69f063f116462c49892b0149e21b6c0a0e", - "sha256:ecd85a8d3e79cd7158dec1c9e5808e821feea088e2f69a974db5edf84dc53141", - "sha256:f5b92f4d70791b4a67157321c4e8225d60b119c5cc9aee8ecf153aace4aad4ef", - "sha256:f5f0c3e969c8f12dd2bb7e0b15d5c468b51e5017e01e2e867335c81903046a22", - "sha256:f7baece4ce06bade126fb84b8af1c33439a76d8a6fd818970215e0560ca28c27", - "sha256:ff25afb18123cea58a591ea0244b92eb1e61a1fd497bf6d6384f09bc3262ec3e", - "sha256:ff337c552345e95702c5fde3158acb0625111017d0e5f24bf3acdb9cc16b90d1" - ], - "markers": "python_version >= '3.8'", - "version": "==10.4.0" - }, "prometheus-client": { "hashes": [ - "sha256:287629d00b147a32dcb2be0b9df905da599b2d82f80377083ec8463309a4bb89", - "sha256:cde524a85bce83ca359cc837f28b8c0db5cac7aa653a588fd7e84ba061c329e7" + "sha256:4fa6b4dd0ac16d58bb587c04b1caae65b8c5043e85f778f42f5f632f6af2e166", + "sha256:96c83c606b71ff2b0a433c98889d275f51ffec6c5e267de37c7a2b5c9aa9233e" ], "markers": "python_version >= '3.8'", - "version": "==0.20.0" + "version": "==0.21.0" }, "prometheus-flask-exporter": { "hashes": [ @@ -1663,70 +1106,109 @@ "index": "pypi", "version": "==0.23.1" }, - "psutil": { - "hashes": [ - "sha256:02b69001f44cc73c1c5279d02b30a817e339ceb258ad75997325e0e6169d8b35", - "sha256:1287c2b95f1c0a364d23bc6f2ea2365a8d4d9b726a3be7294296ff7ba97c17f0", - "sha256:1e7c870afcb7d91fdea2b37c24aeb08f98b6d67257a5cb0a8bc3ac68d0f1a68c", - "sha256:21f1fb635deccd510f69f485b87433460a603919b45e2a324ad65b0cc74f8fb1", - "sha256:33ea5e1c975250a720b3a6609c490db40dae5d83a4eb315170c4fe0d8b1f34b3", - "sha256:34859b8d8f423b86e4385ff3665d3f4d94be3cdf48221fbe476e883514fdb71c", - "sha256:5fd9a97c8e94059b0ef54a7d4baf13b405011176c3b6ff257c247cae0d560ecd", - "sha256:6ec7588fb3ddaec7344a825afe298db83fe01bfaaab39155fa84cf1c0d6b13c3", - "sha256:6ed2440ada7ef7d0d608f20ad89a04ec47d2d3ab7190896cd62ca5fc4fe08bf0", - "sha256:8faae4f310b6d969fa26ca0545338b21f73c6b15db7c4a8d934a5482faa818f2", - "sha256:a021da3e881cd935e64a3d0a20983bda0bb4cf80e4f74fa9bfcb1bc5785360c6", - "sha256:a495580d6bae27291324fe60cea0b5a7c23fa36a7cd35035a16d93bdcf076b9d", - "sha256:a9a3dbfb4de4f18174528d87cc352d1f788b7496991cca33c6996f40c9e3c92c", - "sha256:c588a7e9b1173b6e866756dde596fd4cad94f9399daf99ad8c3258b3cb2b47a0", - "sha256:e2e8d0054fc88153ca0544f5c4d554d42e33df2e009c4ff42284ac9ebdef4132", - "sha256:fc8c9510cde0146432bbdb433322861ee8c3efbf8589865c8bf8d21cb30c4d14", - "sha256:ffe7fc9b6b36beadc8c322f84e1caff51e8703b88eee1da46d1e3a6ae11b4fd0" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", - "version": "==6.0.0" - }, - "pyarrow": { - "hashes": [ - "sha256:0071ce35788c6f9077ff9ecba4858108eebe2ea5a3f7cf2cf55ebc1dbc6ee24a", - "sha256:02dae06ce212d8b3244dd3e7d12d9c4d3046945a5933d28026598e9dbbda1fca", - "sha256:0b72e87fe3e1db343995562f7fff8aee354b55ee83d13afba65400c178ab2597", - "sha256:0cdb0e627c86c373205a2f94a510ac4376fdc523f8bb36beab2e7f204416163c", - "sha256:13d7a460b412f31e4c0efa1148e1d29bdf18ad1411eb6757d38f8fbdcc8645fb", - "sha256:1c8856e2ef09eb87ecf937104aacfa0708f22dfeb039c363ec99735190ffb977", - "sha256:2e19f569567efcbbd42084e87f948778eb371d308e137a0f97afe19bb860ccb3", - "sha256:32503827abbc5aadedfa235f5ece8c4f8f8b0a3cf01066bc8d29de7539532687", - "sha256:392bc9feabc647338e6c89267635e111d71edad5fcffba204425a7c8d13610d7", - "sha256:42bf93249a083aca230ba7e2786c5f673507fa97bbd9725a1e2754715151a204", - "sha256:4beca9521ed2c0921c1023e68d097d0299b62c362639ea315572a58f3f50fd28", - "sha256:5984f416552eea15fd9cee03da53542bf4cddaef5afecefb9aa8d1010c335087", - "sha256:6b244dc8e08a23b3e352899a006a26ae7b4d0da7bb636872fa8f5884e70acf15", - "sha256:757074882f844411fcca735e39aae74248a1531367a7c80799b4266390ae51cc", - "sha256:75c06d4624c0ad6674364bb46ef38c3132768139ddec1c56582dbac54f2663e2", - "sha256:7c7916bff914ac5d4a8fe25b7a25e432ff921e72f6f2b7547d1e325c1ad9d155", - "sha256:9b564a51fbccfab5a04a80453e5ac6c9954a9c5ef2890d1bcf63741909c3f8df", - "sha256:9b8a823cea605221e61f34859dcc03207e52e409ccf6354634143e23af7c8d22", - "sha256:9ba11c4f16976e89146781a83833df7f82077cdab7dc6232c897789343f7891a", - "sha256:a155acc7f154b9ffcc85497509bcd0d43efb80d6f733b0dc3bb14e281f131c8b", - "sha256:a27532c38f3de9eb3e90ecab63dfda948a8ca859a66e3a47f5f42d1e403c4d03", - "sha256:a48ddf5c3c6a6c505904545c25a4ae13646ae1f8ba703c4df4a1bfe4f4006bda", - "sha256:a5c8b238d47e48812ee577ee20c9a2779e6a5904f1708ae240f53ecbee7c9f07", - "sha256:af5ff82a04b2171415f1410cff7ebb79861afc5dae50be73ce06d6e870615204", - "sha256:b0c6ac301093b42d34410b187bba560b17c0330f64907bfa4f7f7f2444b0cf9b", - "sha256:d7d192305d9d8bc9082d10f361fc70a73590a4c65cf31c3e6926cd72b76bc35c", - "sha256:da1e060b3876faa11cee287839f9cc7cdc00649f475714b8680a05fd9071d545", - "sha256:db023dc4c6cae1015de9e198d41250688383c3f9af8f565370ab2b4cb5f62655", - "sha256:dc5c31c37409dfbc5d014047817cb4ccd8c1ea25d19576acf1a001fe07f5b420", - "sha256:dec8d129254d0188a49f8a1fc99e0560dc1b85f60af729f47de4046015f9b0a5", - "sha256:e3343cb1e88bc2ea605986d4b94948716edc7a8d14afd4e2c097232f729758b4", - "sha256:edca18eaca89cd6382dfbcff3dd2d87633433043650c07375d095cd3517561d8", - "sha256:f1e70de6cb5790a50b01d2b686d54aaf73da01266850b05e3af2a1bc89e16053", - "sha256:f553ca691b9e94b202ff741bdd40f6ccb70cdd5fbf65c187af132f1317de6145", - "sha256:f7ae2de664e0b158d1607699a16a488de3d008ba99b3a7aa5de1cbc13574d047", - "sha256:fa3c246cc58cb5a4a5cb407a18f193354ea47dd0648194e6265bd24177982fe8" + "propcache": { + "hashes": [ + "sha256:00181262b17e517df2cd85656fcd6b4e70946fe62cd625b9d74ac9977b64d8d9", + "sha256:0e53cb83fdd61cbd67202735e6a6687a7b491c8742dfc39c9e01e80354956763", + "sha256:1235c01ddaa80da8235741e80815ce381c5267f96cc49b1477fdcf8c047ef325", + "sha256:140fbf08ab3588b3468932974a9331aff43c0ab8a2ec2c608b6d7d1756dbb6cb", + "sha256:191db28dc6dcd29d1a3e063c3be0b40688ed76434622c53a284e5427565bbd9b", + "sha256:1e41d67757ff4fbc8ef2af99b338bfb955010444b92929e9e55a6d4dcc3c4f09", + "sha256:1ec43d76b9677637a89d6ab86e1fef70d739217fefa208c65352ecf0282be957", + "sha256:20a617c776f520c3875cf4511e0d1db847a076d720714ae35ffe0df3e440be68", + "sha256:218db2a3c297a3768c11a34812e63b3ac1c3234c3a086def9c0fee50d35add1f", + "sha256:22aa8f2272d81d9317ff5756bb108021a056805ce63dd3630e27d042c8092798", + "sha256:25a1f88b471b3bc911d18b935ecb7115dff3a192b6fef46f0bfaf71ff4f12418", + "sha256:25c8d773a62ce0451b020c7b29a35cfbc05de8b291163a7a0f3b7904f27253e6", + "sha256:2a60ad3e2553a74168d275a0ef35e8c0a965448ffbc3b300ab3a5bb9956c2162", + "sha256:2a66df3d4992bc1d725b9aa803e8c5a66c010c65c741ad901e260ece77f58d2f", + "sha256:2ccc28197af5313706511fab3a8b66dcd6da067a1331372c82ea1cb74285e036", + "sha256:2e900bad2a8456d00a113cad8c13343f3b1f327534e3589acc2219729237a2e8", + "sha256:2ee7606193fb267be4b2e3b32714f2d58cad27217638db98a60f9efb5efeccc2", + "sha256:33ac8f098df0585c0b53009f039dfd913b38c1d2edafed0cedcc0c32a05aa110", + "sha256:3444cdba6628accf384e349014084b1cacd866fbb88433cd9d279d90a54e0b23", + "sha256:363ea8cd3c5cb6679f1c2f5f1f9669587361c062e4899fce56758efa928728f8", + "sha256:375a12d7556d462dc64d70475a9ee5982465fbb3d2b364f16b86ba9135793638", + "sha256:388f3217649d6d59292b722d940d4d2e1e6a7003259eb835724092a1cca0203a", + "sha256:3947483a381259c06921612550867b37d22e1df6d6d7e8361264b6d037595f44", + "sha256:39e104da444a34830751715f45ef9fc537475ba21b7f1f5b0f4d71a3b60d7fe2", + "sha256:3c997f8c44ec9b9b0bcbf2d422cc00a1d9b9c681f56efa6ca149a941e5560da2", + "sha256:3dfafb44f7bb35c0c06eda6b2ab4bfd58f02729e7c4045e179f9a861b07c9850", + "sha256:3ebbcf2a07621f29638799828b8d8668c421bfb94c6cb04269130d8de4fb7136", + "sha256:3f88a4095e913f98988f5b338c1d4d5d07dbb0b6bad19892fd447484e483ba6b", + "sha256:439e76255daa0f8151d3cb325f6dd4a3e93043e6403e6491813bcaaaa8733887", + "sha256:4569158070180c3855e9c0791c56be3ceeb192defa2cdf6a3f39e54319e56b89", + "sha256:466c219deee4536fbc83c08d09115249db301550625c7fef1c5563a584c9bc87", + "sha256:4a9d9b4d0a9b38d1c391bb4ad24aa65f306c6f01b512e10a8a34a2dc5675d348", + "sha256:4c7dde9e533c0a49d802b4f3f218fa9ad0a1ce21f2c2eb80d5216565202acab4", + "sha256:53d1bd3f979ed529f0805dd35ddaca330f80a9a6d90bc0121d2ff398f8ed8861", + "sha256:55346705687dbd7ef0d77883ab4f6fabc48232f587925bdaf95219bae072491e", + "sha256:56295eb1e5f3aecd516d91b00cfd8bf3a13991de5a479df9e27dd569ea23959c", + "sha256:56bb5c98f058a41bb58eead194b4db8c05b088c93d94d5161728515bd52b052b", + "sha256:5a5b3bb545ead161be780ee85a2b54fdf7092815995661947812dde94a40f6fb", + "sha256:5f2564ec89058ee7c7989a7b719115bdfe2a2fb8e7a4543b8d1c0cc4cf6478c1", + "sha256:608cce1da6f2672a56b24a015b42db4ac612ee709f3d29f27a00c943d9e851de", + "sha256:63f13bf09cc3336eb04a837490b8f332e0db41da66995c9fd1ba04552e516354", + "sha256:662dd62358bdeaca0aee5761de8727cfd6861432e3bb828dc2a693aa0471a563", + "sha256:676135dcf3262c9c5081cc8f19ad55c8a64e3f7282a21266d05544450bffc3a5", + "sha256:67aeb72e0f482709991aa91345a831d0b707d16b0257e8ef88a2ad246a7280bf", + "sha256:67b69535c870670c9f9b14a75d28baa32221d06f6b6fa6f77a0a13c5a7b0a5b9", + "sha256:682a7c79a2fbf40f5dbb1eb6bfe2cd865376deeac65acf9beb607505dced9e12", + "sha256:6994984550eaf25dd7fc7bd1b700ff45c894149341725bb4edc67f0ffa94efa4", + "sha256:69d3a98eebae99a420d4b28756c8ce6ea5a29291baf2dc9ff9414b42676f61d5", + "sha256:6e2e54267980349b723cff366d1e29b138b9a60fa376664a157a342689553f71", + "sha256:73e4b40ea0eda421b115248d7e79b59214411109a5bc47d0d48e4c73e3b8fcf9", + "sha256:74acd6e291f885678631b7ebc85d2d4aec458dd849b8c841b57ef04047833bed", + "sha256:7665f04d0c7f26ff8bb534e1c65068409bf4687aa2534faf7104d7182debb336", + "sha256:7735e82e3498c27bcb2d17cb65d62c14f1100b71723b68362872bca7d0913d90", + "sha256:77a86c261679ea5f3896ec060be9dc8e365788248cc1e049632a1be682442063", + "sha256:7cf18abf9764746b9c8704774d8b06714bcb0a63641518a3a89c7f85cc02c2ad", + "sha256:83928404adf8fb3d26793665633ea79b7361efa0287dfbd372a7e74311d51ee6", + "sha256:8e40876731f99b6f3c897b66b803c9e1c07a989b366c6b5b475fafd1f7ba3fb8", + "sha256:8f188cfcc64fb1266f4684206c9de0e80f54622c3f22a910cbd200478aeae61e", + "sha256:91997d9cb4a325b60d4e3f20967f8eb08dfcb32b22554d5ef78e6fd1dda743a2", + "sha256:91ee8fc02ca52e24bcb77b234f22afc03288e1dafbb1f88fe24db308910c4ac7", + "sha256:92fe151145a990c22cbccf9ae15cae8ae9eddabfc949a219c9f667877e40853d", + "sha256:945db8ee295d3af9dbdbb698cce9bbc5c59b5c3fe328bbc4387f59a8a35f998d", + "sha256:9517d5e9e0731957468c29dbfd0f976736a0e55afaea843726e887f36fe017df", + "sha256:952e0d9d07609d9c5be361f33b0d6d650cd2bae393aabb11d9b719364521984b", + "sha256:97a58a28bcf63284e8b4d7b460cbee1edaab24634e82059c7b8c09e65284f178", + "sha256:97e48e8875e6c13909c800fa344cd54cc4b2b0db1d5f911f840458a500fde2c2", + "sha256:9e0f07b42d2a50c7dd2d8675d50f7343d998c64008f1da5fef888396b7f84630", + "sha256:a3dc1a4b165283bd865e8f8cb5f0c64c05001e0718ed06250d8cac9bec115b48", + "sha256:a3ebe9a75be7ab0b7da2464a77bb27febcb4fab46a34f9288f39d74833db7f61", + "sha256:a64e32f8bd94c105cc27f42d3b658902b5bcc947ece3c8fe7bc1b05982f60e89", + "sha256:a6ed8db0a556343d566a5c124ee483ae113acc9a557a807d439bcecc44e7dfbb", + "sha256:ad9c9b99b05f163109466638bd30ada1722abb01bbb85c739c50b6dc11f92dc3", + "sha256:b33d7a286c0dc1a15f5fc864cc48ae92a846df287ceac2dd499926c3801054a6", + "sha256:bc092ba439d91df90aea38168e11f75c655880c12782facf5cf9c00f3d42b562", + "sha256:c436130cc779806bdf5d5fae0d848713105472b8566b75ff70048c47d3961c5b", + "sha256:c5869b8fd70b81835a6f187c5fdbe67917a04d7e52b6e7cc4e5fe39d55c39d58", + "sha256:c5ecca8f9bab618340c8e848d340baf68bcd8ad90a8ecd7a4524a81c1764b3db", + "sha256:cfac69017ef97db2438efb854edf24f5a29fd09a536ff3a992b75990720cdc99", + "sha256:d2f0d0f976985f85dfb5f3d685697ef769faa6b71993b46b295cdbbd6be8cc37", + "sha256:d5bed7f9805cc29c780f3aee05de3262ee7ce1f47083cfe9f77471e9d6777e83", + "sha256:d6a21ef516d36909931a2967621eecb256018aeb11fc48656e3257e73e2e247a", + "sha256:d9b6ddac6408194e934002a69bcaadbc88c10b5f38fb9307779d1c629181815d", + "sha256:db47514ffdbd91ccdc7e6f8407aac4ee94cc871b15b577c1c324236b013ddd04", + "sha256:df81779732feb9d01e5d513fad0122efb3d53bbc75f61b2a4f29a020bc985e70", + "sha256:e4a91d44379f45f5e540971d41e4626dacd7f01004826a18cb048e7da7e96544", + "sha256:e63e3e1e0271f374ed489ff5ee73d4b6e7c60710e1f76af5f0e1a6117cd26394", + "sha256:e70fac33e8b4ac63dfc4c956fd7d85a0b1139adcfc0d964ce288b7c527537fea", + "sha256:ecddc221a077a8132cf7c747d5352a15ed763b674c0448d811f408bf803d9ad7", + "sha256:f45eec587dafd4b2d41ac189c2156461ebd0c1082d2fe7013571598abb8505d1", + "sha256:f52a68c21363c45297aca15561812d542f8fc683c85201df0bebe209e349f793", + "sha256:f571aea50ba5623c308aa146eb650eebf7dbe0fd8c5d946e28343cb3b5aad577", + "sha256:f60f0ac7005b9f5a6091009b09a419ace1610e163fa5deaba5ce3484341840e7", + "sha256:f6475a1b2ecb310c98c28d271a30df74f9dd436ee46d09236a6b750a7599ce57", + "sha256:f6d5749fdd33d90e34c2efb174c7e236829147a2713334d708746e94c4bde40d", + "sha256:f902804113e032e2cdf8c71015651c97af6418363bea8d78dc0911d56c335032", + "sha256:fa1076244f54bb76e65e22cb6910365779d5c3d71d1f18b275f1dfc7b0d71b4d", + "sha256:fc2db02409338bf36590aa985a461b2c96fce91f8e7e0f14c50c5fcc4f229016", + "sha256:ffcad6c564fe6b9b8916c1aefbb37a362deebf9394bd2974e9d84232e3e08504" ], "markers": "python_version >= '3.8'", - "version": "==17.0.0" + "version": "==0.2.0" }, "pycparser": { "hashes": [ @@ -1738,145 +1220,145 @@ }, "pycryptodome": { "hashes": [ - "sha256:06d6de87c19f967f03b4cf9b34e538ef46e99a337e9a61a77dbe44b2cbcf0690", - "sha256:09609209ed7de61c2b560cc5c8c4fbf892f8b15b1faf7e4cbffac97db1fffda7", - "sha256:210ba1b647837bfc42dd5a813cdecb5b86193ae11a3f5d972b9a0ae2c7e9e4b4", - "sha256:2a1250b7ea809f752b68e3e6f3fd946b5939a52eaeea18c73bdab53e9ba3c2dd", - "sha256:2ab6ab0cb755154ad14e507d1df72de9897e99fd2d4922851a276ccc14f4f1a5", - "sha256:3427d9e5310af6680678f4cce149f54e0bb4af60101c7f2c16fdf878b39ccccc", - "sha256:3cd3ef3aee1079ae44afaeee13393cf68b1058f70576b11439483e34f93cf818", - "sha256:405002eafad114a2f9a930f5db65feef7b53c4784495dd8758069b89baf68eab", - "sha256:417a276aaa9cb3be91f9014e9d18d10e840a7a9b9a9be64a42f553c5b50b4d1d", - "sha256:4401564ebf37dfde45d096974c7a159b52eeabd9969135f0426907db367a652a", - "sha256:49a4c4dc60b78ec41d2afa392491d788c2e06edf48580fbfb0dd0f828af49d25", - "sha256:5601c934c498cd267640b57569e73793cb9a83506f7c73a8ec57a516f5b0b091", - "sha256:6e0e4a987d38cfc2e71b4a1b591bae4891eeabe5fa0f56154f576e26287bfdea", - "sha256:76658f0d942051d12a9bd08ca1b6b34fd762a8ee4240984f7c06ddfb55eaf15a", - "sha256:76cb39afede7055127e35a444c1c041d2e8d2f1f9c121ecef573757ba4cd2c3c", - "sha256:8d6b98d0d83d21fb757a182d52940d028564efe8147baa9ce0f38d057104ae72", - "sha256:9b3ae153c89a480a0ec402e23db8d8d84a3833b65fa4b15b81b83be9d637aab9", - "sha256:a60fedd2b37b4cb11ccb5d0399efe26db9e0dd149016c1cc6c8161974ceac2d6", - "sha256:ac1c7c0624a862f2e53438a15c9259d1655325fc2ec4392e66dc46cdae24d044", - "sha256:acae12b9ede49f38eb0ef76fdec2df2e94aad85ae46ec85be3648a57f0a7db04", - "sha256:acc2614e2e5346a4a4eab6e199203034924313626f9620b7b4b38e9ad74b7e0c", - "sha256:acf6e43fa75aca2d33e93409f2dafe386fe051818ee79ee8a3e21de9caa2ac9e", - "sha256:baee115a9ba6c5d2709a1e88ffe62b73ecc044852a925dcb67713a288c4ec70f", - "sha256:c18b381553638414b38705f07d1ef0a7cf301bc78a5f9bc17a957eb19446834b", - "sha256:d29daa681517f4bc318cd8a23af87e1f2a7bad2fe361e8aa29c77d652a065de4", - "sha256:d5954acfe9e00bc83ed9f5cb082ed22c592fbbef86dc48b907238be64ead5c33", - "sha256:ec0bb1188c1d13426039af8ffcb4dbe3aad1d7680c35a62d8eaf2a529b5d3d4f", - "sha256:ec1f93feb3bb93380ab0ebf8b859e8e5678c0f010d2d78367cf6bc30bfeb148e", - "sha256:f0e6d631bae3f231d3634f91ae4da7a960f7ff87f2865b2d2b831af1dfb04e9a", - "sha256:f35d6cee81fa145333137009d9c8ba90951d7d77b67c79cbe5f03c7eb74d8fe2", - "sha256:f47888542a0633baff535a04726948e876bf1ed880fddb7c10a736fa99146ab3", - "sha256:fb3b87461fa35afa19c971b0a2b7456a7b1db7b4eba9a8424666104925b78128" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==3.20.0" + "sha256:0714206d467fc911042d01ea3a1847c847bc10884cf674c82e12915cfe1649f8", + "sha256:0fa0a05a6a697ccbf2a12cec3d6d2650b50881899b845fac6e87416f8cb7e87d", + "sha256:0fd54003ec3ce4e0f16c484a10bc5d8b9bd77fa662a12b85779a2d2d85d67ee0", + "sha256:18caa8cfbc676eaaf28613637a89980ad2fd96e00c564135bf90bc3f0b34dd93", + "sha256:2480ec2c72438430da9f601ebc12c518c093c13111a5c1644c82cdfc2e50b1e4", + "sha256:26412b21df30b2861424a6c6d5b1d8ca8107612a4cfa4d0183e71c5d200fb34a", + "sha256:280b67d20e33bb63171d55b1067f61fbd932e0b1ad976b3a184303a3dad22764", + "sha256:2cb635b67011bc147c257e61ce864879ffe6d03342dc74b6045059dfbdedafca", + "sha256:2de4b7263a33947ff440412339cb72b28a5a4c769b5c1ca19e33dd6cd1dcec6e", + "sha256:3ba4cc304eac4d4d458f508d4955a88ba25026890e8abff9b60404f76a62c55e", + "sha256:4c26a2f0dc15f81ea3afa3b0c87b87e501f235d332b7f27e2225ecb80c0b1cdd", + "sha256:590ef0898a4b0a15485b05210b4a1c9de8806d3ad3d47f74ab1dc07c67a6827f", + "sha256:5dfafca172933506773482b0e18f0cd766fd3920bd03ec85a283df90d8a17bc6", + "sha256:6cce52e196a5f1d6797ff7946cdff2038d3b5f0aba4a43cb6bf46b575fd1b5bb", + "sha256:7cb087b8612c8a1a14cf37dd754685be9a8d9869bed2ffaaceb04850a8aeef7e", + "sha256:7d85c1b613121ed3dbaa5a97369b3b757909531a959d229406a75b912dd51dd1", + "sha256:7ee86cbde706be13f2dec5a42b52b1c1d1cbb90c8e405c68d0755134735c8dc6", + "sha256:8898a66425a57bcf15e25fc19c12490b87bd939800f39a03ea2de2aea5e3611a", + "sha256:8acd7d34af70ee63f9a849f957558e49a98f8f1634f86a59d2be62bb8e93f71c", + "sha256:932c905b71a56474bff8a9c014030bc3c882cee696b448af920399f730a650c2", + "sha256:a1752eca64c60852f38bb29e2c86fca30d7672c024128ef5d70cc15868fa10f4", + "sha256:a3804675283f4764a02db05f5191eb8fec2bb6ca34d466167fc78a5f05bbe6b3", + "sha256:a4e74c522d630766b03a836c15bff77cb657c5fdf098abf8b1ada2aebc7d0819", + "sha256:a915597ffccabe902e7090e199a7bf7a381c5506a747d5e9d27ba55197a2c568", + "sha256:b7aa25fc0baa5b1d95b7633af4f5f1838467f1815442b22487426f94e0d66c53", + "sha256:cc2269ab4bce40b027b49663d61d816903a4bd90ad88cb99ed561aadb3888dd3", + "sha256:d5ebe0763c982f069d3877832254f64974139f4f9655058452603ff559c482e8", + "sha256:dad9bf36eda068e89059d1f07408e397856be9511d7113ea4b586642a429a4fd", + "sha256:de18954104667f565e2fbb4783b56667f30fb49c4d79b346f52a29cb198d5b6b", + "sha256:f35e442630bc4bc2e1878482d6f59ea22e280d7121d7adeaedba58c23ab6386b", + "sha256:f7787e0d469bdae763b876174cf2e6c0f7be79808af26b1da96f1a64bcf47297", + "sha256:ff99f952db3db2fbe98a0b355175f93ec334ba3d01bbde25ad3a5a33abc02b58" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", + "version": "==3.21.0" }, "pydantic": { "hashes": [ - "sha256:6f62c13d067b0755ad1c21a34bdd06c0c12625a22b0fc09c6b149816604f7c2a", - "sha256:73ee9fddd406dc318b885c7a2eab8a6472b68b8fb5ba8150949fc3db939f23c8" + "sha256:d155cef71265d1e9807ed1c32b4c8deec042a44a50a4188b25ac67ecd81a9c0f", + "sha256:f048cec7b26778210e28a0459867920654d48e5e62db0958433636cde4254f12" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==2.8.2" + "version": "==2.9.2" }, "pydantic-core": { "hashes": [ - "sha256:035ede2e16da7281041f0e626459bcae33ed998cca6a0a007a5ebb73414ac72d", - "sha256:04024d270cf63f586ad41fff13fde4311c4fc13ea74676962c876d9577bcc78f", - "sha256:0827505a5c87e8aa285dc31e9ec7f4a17c81a813d45f70b1d9164e03a813a686", - "sha256:084659fac3c83fd674596612aeff6041a18402f1e1bc19ca39e417d554468482", - "sha256:10d4204d8ca33146e761c79f83cc861df20e7ae9f6487ca290a97702daf56006", - "sha256:11b71d67b4725e7e2a9f6e9c0ac1239bbc0c48cce3dc59f98635efc57d6dac83", - "sha256:150906b40ff188a3260cbee25380e7494ee85048584998c1e66df0c7a11c17a6", - "sha256:175873691124f3d0da55aeea1d90660a6ea7a3cfea137c38afa0a5ffabe37b88", - "sha256:177f55a886d74f1808763976ac4efd29b7ed15c69f4d838bbd74d9d09cf6fa86", - "sha256:19c0fa39fa154e7e0b7f82f88ef85faa2a4c23cc65aae2f5aea625e3c13c735a", - "sha256:1eedfeb6089ed3fad42e81a67755846ad4dcc14d73698c120a82e4ccf0f1f9f6", - "sha256:225b67a1f6d602de0ce7f6c1c3ae89a4aa25d3de9be857999e9124f15dab486a", - "sha256:242b8feb3c493ab78be289c034a1f659e8826e2233786e36f2893a950a719bb6", - "sha256:254ec27fdb5b1ee60684f91683be95e5133c994cc54e86a0b0963afa25c8f8a6", - "sha256:25e9185e2d06c16ee438ed39bf62935ec436474a6ac4f9358524220f1b236e43", - "sha256:26ab812fa0c845df815e506be30337e2df27e88399b985d0bb4e3ecfe72df31c", - "sha256:26ca695eeee5f9f1aeeb211ffc12f10bcb6f71e2989988fda61dabd65db878d4", - "sha256:26dc97754b57d2fd00ac2b24dfa341abffc380b823211994c4efac7f13b9e90e", - "sha256:270755f15174fb983890c49881e93f8f1b80f0b5e3a3cc1394a255706cabd203", - "sha256:2aafc5a503855ea5885559eae883978c9b6d8c8993d67766ee73d82e841300dd", - "sha256:2d036c7187b9422ae5b262badb87a20a49eb6c5238b2004e96d4da1231badef1", - "sha256:33499e85e739a4b60c9dac710c20a08dc73cb3240c9a0e22325e671b27b70d24", - "sha256:37eee5b638f0e0dcd18d21f59b679686bbd18917b87db0193ae36f9c23c355fc", - "sha256:38cf1c40a921d05c5edc61a785c0ddb4bed67827069f535d794ce6bcded919fc", - "sha256:3acae97ffd19bf091c72df4d726d552c473f3576409b2a7ca36b2f535ffff4a3", - "sha256:3c5ebac750d9d5f2706654c638c041635c385596caf68f81342011ddfa1e5598", - "sha256:3d482efec8b7dc6bfaedc0f166b2ce349df0011f5d2f1f25537ced4cfc34fd98", - "sha256:407653af5617f0757261ae249d3fba09504d7a71ab36ac057c938572d1bc9331", - "sha256:40a783fb7ee353c50bd3853e626f15677ea527ae556429453685ae32280c19c2", - "sha256:41e81317dd6a0127cabce83c0c9c3fbecceae981c8391e6f1dec88a77c8a569a", - "sha256:41f4c96227a67a013e7de5ff8f20fb496ce573893b7f4f2707d065907bffdbd6", - "sha256:469f29f9093c9d834432034d33f5fe45699e664f12a13bf38c04967ce233d688", - "sha256:4745f4ac52cc6686390c40eaa01d48b18997cb130833154801a442323cc78f91", - "sha256:4868f6bd7c9d98904b748a2653031fc9c2f85b6237009d475b1008bfaeb0a5aa", - "sha256:4aa223cd1e36b642092c326d694d8bf59b71ddddc94cdb752bbbb1c5c91d833b", - "sha256:4dd484681c15e6b9a977c785a345d3e378d72678fd5f1f3c0509608da24f2ac0", - "sha256:4f2790949cf385d985a31984907fecb3896999329103df4e4983a4a41e13e840", - "sha256:512ecfbefef6dac7bc5eaaf46177b2de58cdf7acac8793fe033b24ece0b9566c", - "sha256:516d9227919612425c8ef1c9b869bbbee249bc91912c8aaffb66116c0b447ebd", - "sha256:53e431da3fc53360db73eedf6f7124d1076e1b4ee4276b36fb25514544ceb4a3", - "sha256:595ba5be69b35777474fa07f80fc260ea71255656191adb22a8c53aba4479231", - "sha256:5b5ff4911aea936a47d9376fd3ab17e970cc543d1b68921886e7f64bd28308d1", - "sha256:5d41e6daee2813ecceea8eda38062d69e280b39df793f5a942fa515b8ed67953", - "sha256:5e999ba8dd90e93d57410c5e67ebb67ffcaadcea0ad973240fdfd3a135506250", - "sha256:5f239eb799a2081495ea659d8d4a43a8f42cd1fe9ff2e7e436295c38a10c286a", - "sha256:635fee4e041ab9c479e31edda27fcf966ea9614fff1317e280d99eb3e5ab6fe2", - "sha256:65db0f2eefcaad1a3950f498aabb4875c8890438bc80b19362cf633b87a8ab20", - "sha256:6b507132dcfc0dea440cce23ee2182c0ce7aba7054576efc65634f080dbe9434", - "sha256:6b9d9bb600328a1ce523ab4f454859e9d439150abb0906c5a1983c146580ebab", - "sha256:70c8daf4faca8da5a6d655f9af86faf6ec2e1768f4b8b9d0226c02f3d6209703", - "sha256:77bf3ac639c1ff567ae3b47f8d4cc3dc20f9966a2a6dd2311dcc055d3d04fb8a", - "sha256:784c1214cb6dd1e3b15dd8b91b9a53852aed16671cc3fbe4786f4f1db07089e2", - "sha256:7eb6a0587eded33aeefea9f916899d42b1799b7b14b8f8ff2753c0ac1741edac", - "sha256:7ed1b0132f24beeec5a78b67d9388656d03e6a7c837394f99257e2d55b461611", - "sha256:8ad4aeb3e9a97286573c03df758fc7627aecdd02f1da04516a86dc159bf70121", - "sha256:964faa8a861d2664f0c7ab0c181af0bea66098b1919439815ca8803ef136fc4e", - "sha256:9dc1b507c12eb0481d071f3c1808f0529ad41dc415d0ca11f7ebfc666e66a18b", - "sha256:9ebfef07dbe1d93efb94b4700f2d278494e9162565a54f124c404a5656d7ff09", - "sha256:a45f84b09ac9c3d35dfcf6a27fd0634d30d183205230a0ebe8373a0e8cfa0906", - "sha256:a4f55095ad087474999ee28d3398bae183a66be4823f753cd7d67dd0153427c9", - "sha256:a6d511cc297ff0883bc3708b465ff82d7560193169a8b93260f74ecb0a5e08a7", - "sha256:a8ad4c766d3f33ba8fd692f9aa297c9058970530a32c728a2c4bfd2616d3358b", - "sha256:aa2f457b4af386254372dfa78a2eda2563680d982422641a85f271c859df1987", - "sha256:b03f7941783b4c4a26051846dea594628b38f6940a2fdc0df00b221aed39314c", - "sha256:b0dae11d8f5ded51699c74d9548dcc5938e0804cc8298ec0aa0da95c21fff57b", - "sha256:b91ced227c41aa29c672814f50dbb05ec93536abf8f43cd14ec9521ea09afe4e", - "sha256:bc633a9fe1eb87e250b5c57d389cf28998e4292336926b0b6cdaee353f89a237", - "sha256:bebb4d6715c814597f85297c332297c6ce81e29436125ca59d1159b07f423eb1", - "sha256:c336a6d235522a62fef872c6295a42ecb0c4e1d0f1a3e500fe949415761b8a19", - "sha256:c6514f963b023aeee506678a1cf821fe31159b925c4b76fe2afa94cc70b3222b", - "sha256:c693e916709c2465b02ca0ad7b387c4f8423d1db7b4649c551f27a529181c5ad", - "sha256:c81131869240e3e568916ef4c307f8b99583efaa60a8112ef27a366eefba8ef0", - "sha256:d02a72df14dfdbaf228424573a07af10637bd490f0901cee872c4f434a735b94", - "sha256:d2a8fa9d6d6f891f3deec72f5cc668e6f66b188ab14bb1ab52422fe8e644f312", - "sha256:d2b27e6af28f07e2f195552b37d7d66b150adbaa39a6d327766ffd695799780f", - "sha256:d2fe69c5434391727efa54b47a1e7986bb0186e72a41b203df8f5b0a19a4f669", - "sha256:d3f3ed29cd9f978c604708511a1f9c2fdcb6c38b9aae36a51905b8811ee5cbf1", - "sha256:d573faf8eb7e6b1cbbcb4f5b247c60ca8be39fe2c674495df0eb4318303137fe", - "sha256:e0bbdd76ce9aa5d4209d65f2b27fc6e5ef1312ae6c5333c26db3f5ade53a1e99", - "sha256:e7c4ea22b6739b162c9ecaaa41d718dfad48a244909fe7ef4b54c0b530effc5a", - "sha256:e93e1a4b4b33daed65d781a57a522ff153dcf748dee70b40c7258c5861e1768a", - "sha256:e97fdf088d4b31ff4ba35db26d9cc472ac7ef4a2ff2badeabf8d727b3377fc52", - "sha256:e9fa4c9bf273ca41f940bceb86922a7667cd5bf90e95dbb157cbb8441008482c", - "sha256:eaad4ff2de1c3823fddf82f41121bdf453d922e9a238642b1dedb33c4e4f98ad", - "sha256:f1f62b2413c3a0e846c3b838b2ecd6c7a19ec6793b2a522745b0869e37ab5bc1", - "sha256:f6d6cff3538391e8486a431569b77921adfcdef14eb18fbf19b7c0a5294d4e6a", - "sha256:f9aa05d09ecf4c75157197f27cdc9cfaeb7c5f15021c6373932bf3e124af029f", - "sha256:fa2fddcb7107e0d1808086ca306dcade7df60a13a6c347a7acf1ec139aa6789a", - "sha256:faa6b09ee09433b87992fb5a2859efd1c264ddc37280d2dd5db502126d0e7f27" + "sha256:0a7df63886be5e270da67e0966cf4afbae86069501d35c8c1b3b6c168f42cb36", + "sha256:0cb3da3fd1b6a5d0279a01877713dbda118a2a4fc6f0d821a57da2e464793f05", + "sha256:0dbd8dbed2085ed23b5c04afa29d8fd2771674223135dc9bc937f3c09284d071", + "sha256:0dff76e0602ca7d4cdaacc1ac4c005e0ce0dcfe095d5b5259163a80d3a10d327", + "sha256:1278e0d324f6908e872730c9102b0112477a7f7cf88b308e4fc36ce1bdb6d58c", + "sha256:128585782e5bfa515c590ccee4b727fb76925dd04a98864182b22e89a4e6ed36", + "sha256:1498bec4c05c9c787bde9125cfdcc63a41004ff167f495063191b863399b1a29", + "sha256:19442362866a753485ba5e4be408964644dd6a09123d9416c54cd49171f50744", + "sha256:1b84d168f6c48fabd1f2027a3d1bdfe62f92cade1fb273a5d68e621da0e44e6d", + "sha256:1e90d2e3bd2c3863d48525d297cd143fe541be8bbf6f579504b9712cb6b643ec", + "sha256:20152074317d9bed6b7a95ade3b7d6054845d70584216160860425f4fbd5ee9e", + "sha256:216f9b2d7713eb98cb83c80b9c794de1f6b7e3145eef40400c62e86cee5f4e1e", + "sha256:233710f069d251feb12a56da21e14cca67994eab08362207785cf8c598e74577", + "sha256:255a8ef062cbf6674450e668482456abac99a5583bbafb73f9ad469540a3a232", + "sha256:2584f7cf844ac4d970fba483a717dbe10c1c1c96a969bf65d61ffe94df1b2863", + "sha256:2971bb5ffe72cc0f555c13e19b23c85b654dd2a8f7ab493c262071377bfce9f6", + "sha256:29d2c342c4bc01b88402d60189f3df065fb0dda3654744d5a165a5288a657368", + "sha256:2e203fdf807ac7e12ab59ca2bfcabb38c7cf0b33c41efeb00f8e5da1d86af480", + "sha256:33e3d65a85a2a4a0dc3b092b938a4062b1a05f3a9abde65ea93b233bca0e03f2", + "sha256:374a5e5049eda9e0a44c696c7ade3ff355f06b1fe0bb945ea3cac2bc336478a2", + "sha256:37b0fe330e4a58d3c58b24d91d1eb102aeec675a3db4c292ec3928ecd892a9a6", + "sha256:3d5639516376dce1940ea36edf408c554475369f5da2abd45d44621cb616f769", + "sha256:42c6dcb030aefb668a2b7009c85b27f90e51e6a3b4d5c9bc4c57631292015b0d", + "sha256:4a7cd62e831afe623fbb7aabbb4fe583212115b3ef38a9f6b71869ba644624a2", + "sha256:4ba762ed58e8d68657fc1281e9bb72e1c3e79cc5d464be146e260c541ec12d84", + "sha256:4fc714bdbfb534f94034efaa6eadd74e5b93c8fa6315565a222f7b6f42ca1166", + "sha256:4ffa2ebd4c8530079140dd2d7f794a9d9a73cbb8e9d59ffe24c63436efa8f271", + "sha256:5a1504ad17ba4210df3a045132a7baeeba5a200e930f57512ee02909fc5c4cb5", + "sha256:5c364564d17da23db1106787675fc7af45f2f7b58b4173bfdd105564e132e6fb", + "sha256:5e11661ce0fd30a6790e8bcdf263b9ec5988e95e63cf901972107efc49218b13", + "sha256:5f54b118ce5de9ac21c363d9b3caa6c800341e8c47a508787e5868c6b79c9323", + "sha256:5f5ff8d839f4566a474a969508fe1c5e59c31c80d9e140566f9a37bba7b8d556", + "sha256:61817945f2fe7d166e75fbfb28004034b48e44878177fc54d81688e7b85a3665", + "sha256:624e278a7d29b6445e4e813af92af37820fafb6dcc55c012c834f9e26f9aaaef", + "sha256:63e46b3169866bd62849936de036f901a9356e36376079b05efa83caeaa02ceb", + "sha256:6531b7ca5f951d663c339002e91aaebda765ec7d61b7d1e3991051906ddde119", + "sha256:68665f4c17edcceecc112dfed5dbe6f92261fb9d6054b47d01bf6371a6196126", + "sha256:696dd8d674d6ce621ab9d45b205df149399e4bb9aa34102c970b721554828510", + "sha256:6f783e0ec4803c787bcea93e13e9932edab72068f68ecffdf86a99fd5918878b", + "sha256:723314c1d51722ab28bfcd5240d858512ffd3116449c557a1336cbe3919beb87", + "sha256:74b9127ffea03643e998e0c5ad9bd3811d3dac8c676e47db17b0ee7c3c3bf35f", + "sha256:7530e201d10d7d14abce4fb54cfe5b94a0aefc87da539d0346a484ead376c3cc", + "sha256:77733e3892bb0a7fa797826361ce8a9184d25c8dffaec60b7ffe928153680ba8", + "sha256:78ddaaa81421a29574a682b3179d4cf9e6d405a09b99d93ddcf7e5239c742e21", + "sha256:7c9129eb40958b3d4500fa2467e6a83356b3b61bfff1b414c7361d9220f9ae8f", + "sha256:7d32706badfe136888bdea71c0def994644e09fff0bfe47441deaed8e96fdbc6", + "sha256:81965a16b675b35e1d09dd14df53f190f9129c0202356ed44ab2728b1c905658", + "sha256:8394d940e5d400d04cad4f75c0598665cbb81aecefaca82ca85bd28264af7f9b", + "sha256:86d2f57d3e1379a9525c5ab067b27dbb8a0642fb5d454e17a9ac434f9ce523e3", + "sha256:883a91b5dd7d26492ff2f04f40fbb652de40fcc0afe07e8129e8ae779c2110eb", + "sha256:88ad334a15b32a791ea935af224b9de1bf99bcd62fabf745d5f3442199d86d59", + "sha256:9261d3ce84fa1d38ed649c3638feefeae23d32ba9182963e465d58d62203bd24", + "sha256:97df63000f4fea395b2824da80e169731088656d1818a11b95f3b173747b6cd9", + "sha256:98d134c954828488b153d88ba1f34e14259284f256180ce659e8d83e9c05eaa3", + "sha256:996a38a83508c54c78a5f41456b0103c30508fed9abcad0a59b876d7398f25fd", + "sha256:9a5bce9d23aac8f0cf0836ecfc033896aa8443b501c58d0602dbfd5bd5b37753", + "sha256:9a6b5099eeec78827553827f4c6b8615978bb4b6a88e5d9b93eddf8bb6790f55", + "sha256:9d18368b137c6295db49ce7218b1a9ba15c5bc254c96d7c9f9e924a9bc7825ad", + "sha256:a4fa4fc04dff799089689f4fd502ce7d59de529fc2f40a2c8836886c03e0175a", + "sha256:a5c7ba8ffb6d6f8f2ab08743be203654bb1aaa8c9dcb09f82ddd34eadb695605", + "sha256:aea443fffa9fbe3af1a9ba721a87f926fe548d32cab71d188a6ede77d0ff244e", + "sha256:b10bd51f823d891193d4717448fab065733958bdb6a6b351967bd349d48d5c9b", + "sha256:ba1a0996f6c2773bd83e63f18914c1de3c9dd26d55f4ac302a7efe93fb8e7433", + "sha256:bb2802e667b7051a1bebbfe93684841cc9351004e2badbd6411bf357ab8d5ac8", + "sha256:cfdd16ab5e59fc31b5e906d1a3f666571abc367598e3e02c83403acabc092e07", + "sha256:d06b0c8da4f16d1d1e352134427cb194a0a6e19ad5db9161bf32b2113409e728", + "sha256:d0776dea117cf5272382634bd2a5c1b6eb16767c223c6a5317cd3e2a757c61a0", + "sha256:d18ca8148bebe1b0a382a27a8ee60350091a6ddaf475fa05ef50dc35b5df6327", + "sha256:d4488a93b071c04dc20f5cecc3631fc78b9789dd72483ba15d423b5b3689b555", + "sha256:d5f7a395a8cf1621939692dba2a6b6a830efa6b3cee787d82c7de1ad2930de64", + "sha256:d7a80d21d613eec45e3d41eb22f8f94ddc758a6c4720842dc74c0581f54993d6", + "sha256:d97683ddee4723ae8c95d1eddac7c192e8c552da0c73a925a89fa8649bf13eea", + "sha256:dcedcd19a557e182628afa1d553c3895a9f825b936415d0dbd3cd0bbcfd29b4b", + "sha256:de6d1d1b9e5101508cb37ab0d972357cac5235f5c6533d1071964c47139257df", + "sha256:df49e7a0861a8c36d089c1ed57d308623d60416dab2647a4a17fe050ba85de0e", + "sha256:df933278128ea1cd77772673c73954e53a1c95a4fdf41eef97c2b779271bd0bd", + "sha256:e08277a400de01bc72436a0ccd02bdf596631411f592ad985dcee21445bd0068", + "sha256:e38e63e6f3d1cec5a27e0afe90a085af8b6806ee208b33030e65b6516353f1a3", + "sha256:e55541f756f9b3ee346b840103f32779c695a19826a4c442b7954550a0972040", + "sha256:ec4e55f79b1c4ffb2eecd8a0cfba9955a2588497d96851f4c8f99aa4a1d39b12", + "sha256:ed1a53de42fbe34853ba90513cea21673481cd81ed1be739f7f2efb931b24916", + "sha256:ed541d70698978a20eb63d8c5d72f2cc6d7079d9d90f6b50bad07826f1320f5f", + "sha256:f09e2ff1f17c2b51f2bc76d1cc33da96298f0a036a137f5440ab3ec5360b624f", + "sha256:f220b0eea5965dec25480b6333c788fb72ce5f9129e8759ef876a1d805d00801", + "sha256:f3e0da4ebaef65158d4dfd7d3678aad692f7666877df0002b8a522cdf088f231", + "sha256:f455ee30a9d61d3e1a15abd5068827773d6e4dc513e795f380cdd59932c782d5", + "sha256:f5ef8f42bec47f21d07668a043f077d507e5bf4e668d5c6dfe6aaba89de1a5b8", + "sha256:f69a8e0b033b747bb3e36a44e7732f0c99f7edd5cea723d45bc0d6e95377ffee", + "sha256:ff02b6d461a6de369f07ec15e465a88895f3223eb75073ffea56b84d9331f607" ], "markers": "python_version >= '3.8'", - "version": "==2.20.1" + "version": "==2.23.4" }, "pyjwt": { "hashes": [ @@ -1886,14 +1368,6 @@ "markers": "python_version >= '3.8'", "version": "==2.9.0" }, - "pyparsing": { - "hashes": [ - "sha256:a1bac0ce561155ecc3ed78ca94d3c9378656ad4c94c1270de543f621420f94ad", - "sha256:f9db75911801ed778fe61bb643079ff86601aca99fcae6345aa67292038fb742" - ], - "markers": "python_full_version >= '3.6.8'", - "version": "==3.1.2" - }, "python-dateutil": { "hashes": [ "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", @@ -1904,10 +1378,10 @@ }, "pytz": { "hashes": [ - "sha256:2a29735ea9c18baf14b448846bde5a48030ed267578472d8955cd0e7443a9812", - "sha256:328171f4e3623139da4983451950b28e95ac706e13f3f2630a879749e7a8b319" + "sha256:2aa355083c50a0f93fa581709deac0c9ad65cca8a9e9beac660adcbd493c798a", + "sha256:31c7c1817eb7fae7ca4b8c7ee50c72f93aa2dd863de768e1ef4245d426aa0725" ], - "version": "==2024.1" + "version": "==2024.2" }, "pyyaml": { "hashes": [ @@ -1976,91 +1450,6 @@ "markers": "python_version >= '3.8'", "version": "==0.35.1" }, - "regex": { - "hashes": [ - "sha256:01b689e887f612610c869421241e075c02f2e3d1ae93a037cb14f88ab6a8934c", - "sha256:04ce29e2c5fedf296b1a1b0acc1724ba93a36fb14031f3abfb7abda2806c1535", - "sha256:0ffe3f9d430cd37d8fa5632ff6fb36d5b24818c5c986893063b4e5bdb84cdf24", - "sha256:18300a1d78cf1290fa583cd8b7cde26ecb73e9f5916690cf9d42de569c89b1ce", - "sha256:185e029368d6f89f36e526764cf12bf8d6f0e3a2a7737da625a76f594bdfcbfc", - "sha256:19c65b00d42804e3fbea9708f0937d157e53429a39b7c61253ff15670ff62cb5", - "sha256:228b0d3f567fafa0633aee87f08b9276c7062da9616931382993c03808bb68ce", - "sha256:23acc72f0f4e1a9e6e9843d6328177ae3074b4182167e34119ec7233dfeccf53", - "sha256:25419b70ba00a16abc90ee5fce061228206173231f004437730b67ac77323f0d", - "sha256:2dfbb8baf8ba2c2b9aa2807f44ed272f0913eeeba002478c4577b8d29cde215c", - "sha256:2f1baff13cc2521bea83ab2528e7a80cbe0ebb2c6f0bfad15be7da3aed443908", - "sha256:33e2614a7ce627f0cdf2ad104797d1f68342d967de3695678c0cb84f530709f8", - "sha256:3426de3b91d1bc73249042742f45c2148803c111d1175b283270177fdf669024", - "sha256:382281306e3adaaa7b8b9ebbb3ffb43358a7bbf585fa93821300a418bb975281", - "sha256:3d974d24edb231446f708c455fd08f94c41c1ff4f04bcf06e5f36df5ef50b95a", - "sha256:3f3b6ca8eae6d6c75a6cff525c8530c60e909a71a15e1b731723233331de4169", - "sha256:3fac296f99283ac232d8125be932c5cd7644084a30748fda013028c815ba3364", - "sha256:416c0e4f56308f34cdb18c3f59849479dde5b19febdcd6e6fa4d04b6c31c9faa", - "sha256:438d9f0f4bc64e8dea78274caa5af971ceff0f8771e1a2333620969936ba10be", - "sha256:43affe33137fcd679bdae93fb25924979517e011f9dea99163f80b82eadc7e53", - "sha256:44fc61b99035fd9b3b9453f1713234e5a7c92a04f3577252b45feefe1b327759", - "sha256:45104baae8b9f67569f0f1dca5e1f1ed77a54ae1cd8b0b07aba89272710db61e", - "sha256:4fdd1384619f406ad9037fe6b6eaa3de2749e2e12084abc80169e8e075377d3b", - "sha256:538d30cd96ed7d1416d3956f94d54e426a8daf7c14527f6e0d6d425fcb4cca52", - "sha256:558a57cfc32adcf19d3f791f62b5ff564922942e389e3cfdb538a23d65a6b610", - "sha256:5eefee9bfe23f6df09ffb6dfb23809f4d74a78acef004aa904dc7c88b9944b05", - "sha256:64bd50cf16bcc54b274e20235bf8edbb64184a30e1e53873ff8d444e7ac656b2", - "sha256:65fd3d2e228cae024c411c5ccdffae4c315271eee4a8b839291f84f796b34eca", - "sha256:66b4c0731a5c81921e938dcf1a88e978264e26e6ac4ec96a4d21ae0354581ae0", - "sha256:68a8f8c046c6466ac61a36b65bb2395c74451df2ffb8458492ef49900efed293", - "sha256:6a1141a1dcc32904c47f6846b040275c6e5de0bf73f17d7a409035d55b76f289", - "sha256:6b9fc7e9cc983e75e2518496ba1afc524227c163e43d706688a6bb9eca41617e", - "sha256:6f51f9556785e5a203713f5efd9c085b4a45aecd2a42573e2b5041881b588d1f", - "sha256:7214477bf9bd195894cf24005b1e7b496f46833337b5dedb7b2a6e33f66d962c", - "sha256:731fcd76bbdbf225e2eb85b7c38da9633ad3073822f5ab32379381e8c3c12e94", - "sha256:74007a5b25b7a678459f06559504f1eec2f0f17bca218c9d56f6a0a12bfffdad", - "sha256:7a5486ca56c8869070a966321d5ab416ff0f83f30e0e2da1ab48815c8d165d46", - "sha256:7c479f5ae937ec9985ecaf42e2e10631551d909f203e31308c12d703922742f9", - "sha256:7df9ea48641da022c2a3c9c641650cd09f0cd15e8908bf931ad538f5ca7919c9", - "sha256:7e37e809b9303ec3a179085415cb5f418ecf65ec98cdfe34f6a078b46ef823ee", - "sha256:80c811cfcb5c331237d9bad3bea2c391114588cf4131707e84d9493064d267f9", - "sha256:836d3cc225b3e8a943d0b02633fb2f28a66e281290302a79df0e1eaa984ff7c1", - "sha256:84c312cdf839e8b579f504afcd7b65f35d60b6285d892b19adea16355e8343c9", - "sha256:86b17ba823ea76256b1885652e3a141a99a5c4422f4a869189db328321b73799", - "sha256:871e3ab2838fbcb4e0865a6e01233975df3a15e6fce93b6f99d75cacbd9862d1", - "sha256:88ecc3afd7e776967fa16c80f974cb79399ee8dc6c96423321d6f7d4b881c92b", - "sha256:8bc593dcce679206b60a538c302d03c29b18e3d862609317cb560e18b66d10cf", - "sha256:8fd5afd101dcf86a270d254364e0e8dddedebe6bd1ab9d5f732f274fa00499a5", - "sha256:945352286a541406f99b2655c973852da7911b3f4264e010218bbc1cc73168f2", - "sha256:973335b1624859cb0e52f96062a28aa18f3a5fc77a96e4a3d6d76e29811a0e6e", - "sha256:994448ee01864501912abf2bad9203bffc34158e80fe8bfb5b031f4f8e16da51", - "sha256:9cfd009eed1a46b27c14039ad5bbc5e71b6367c5b2e6d5f5da0ea91600817506", - "sha256:a2ec4419a3fe6cf8a4795752596dfe0adb4aea40d3683a132bae9c30b81e8d73", - "sha256:a4997716674d36a82eab3e86f8fa77080a5d8d96a389a61ea1d0e3a94a582cf7", - "sha256:a512eed9dfd4117110b1881ba9a59b31433caed0c4101b361f768e7bcbaf93c5", - "sha256:a82465ebbc9b1c5c50738536fdfa7cab639a261a99b469c9d4c7dcbb2b3f1e57", - "sha256:ae2757ace61bc4061b69af19e4689fa4416e1a04840f33b441034202b5cd02d4", - "sha256:b16582783f44fbca6fcf46f61347340c787d7530d88b4d590a397a47583f31dd", - "sha256:ba2537ef2163db9e6ccdbeb6f6424282ae4dea43177402152c67ef869cf3978b", - "sha256:bf7a89eef64b5455835f5ed30254ec19bf41f7541cd94f266ab7cbd463f00c41", - "sha256:c0abb5e4e8ce71a61d9446040c1e86d4e6d23f9097275c5bd49ed978755ff0fe", - "sha256:c414cbda77dbf13c3bc88b073a1a9f375c7b0cb5e115e15d4b73ec3a2fbc6f59", - "sha256:c51edc3541e11fbe83f0c4d9412ef6c79f664a3745fab261457e84465ec9d5a8", - "sha256:c5e69fd3eb0b409432b537fe3c6f44ac089c458ab6b78dcec14478422879ec5f", - "sha256:c918b7a1e26b4ab40409820ddccc5d49871a82329640f5005f73572d5eaa9b5e", - "sha256:c9bb87fdf2ab2370f21e4d5636e5317775e5d51ff32ebff2cf389f71b9b13750", - "sha256:ca5b2028c2f7af4e13fb9fc29b28d0ce767c38c7facdf64f6c2cd040413055f1", - "sha256:d0a07763776188b4db4c9c7fb1b8c494049f84659bb387b71c73bbc07f189e96", - "sha256:d33a0021893ede5969876052796165bab6006559ab845fd7b515a30abdd990dc", - "sha256:d55588cba7553f0b6ec33130bc3e114b355570b45785cebdc9daed8c637dd440", - "sha256:dac8e84fff5d27420f3c1e879ce9929108e873667ec87e0c8eeb413a5311adfe", - "sha256:eaef80eac3b4cfbdd6de53c6e108b4c534c21ae055d1dbea2de6b3b8ff3def38", - "sha256:eb462f0e346fcf41a901a126b50f8781e9a474d3927930f3490f38a6e73b6950", - "sha256:eb563dd3aea54c797adf513eeec819c4213d7dbfc311874eb4fd28d10f2ff0f2", - "sha256:f273674b445bcb6e4409bf8d1be67bc4b58e8b46fd0d560055d515b8830063cd", - "sha256:f6442f0f0ff81775eaa5b05af8a0ffa1dda36e9cf6ec1e0d3d245e8564b684ce", - "sha256:fb168b5924bef397b5ba13aabd8cf5df7d3d93f10218d7b925e360d436863f66", - "sha256:fbf8c2f00904eaf63ff37718eb13acf8e178cb940520e47b2f05027f5bb34ce3", - "sha256:fe4ebef608553aff8deb845c7f4f1d0740ff76fa672c011cc0bacb2a00fbde86" - ], - "markers": "python_version >= '3.8'", - "version": "==2024.7.24" - }, "requests": { "hashes": [ "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", @@ -2181,209 +1570,19 @@ }, "s3transfer": { "hashes": [ - "sha256:0711534e9356d3cc692fdde846b4a1e4b0cb6519971860796e6bc4c7aea00ef6", - "sha256:eca1c20de70a39daee580aef4986996620f365c4e0fda6a86100231d62f1bf69" + "sha256:263ed587a5803c6c708d3ce44dc4dfedaab4c1a32e8329bab818933d79ddcf5d", + "sha256:4f50ed74ab84d474ce614475e0b8d5047ff080810aac5d01ea25231cfc944b0c" ], "markers": "python_version >= '3.8'", - "version": "==0.10.2" - }, - "safetensors": { - "hashes": [ - "sha256:005ef9fc0f47cb9821c40793eb029f712e97278dae84de91cb2b4809b856685d", - "sha256:00eea99ae422fbfa0b46065acbc58b46bfafadfcec179d4b4a32d5c45006af6c", - "sha256:03f2bb92e61b055ef6cc22883ad1ae898010a95730fa988c60a23800eb742c2c", - "sha256:051d5ecd490af7245258000304b812825974d5e56f14a3ff7e1b8b2ba6dc2ed4", - "sha256:063421ef08ca1021feea8b46951251b90ae91f899234dd78297cbe7c1db73b99", - "sha256:0677c109d949cf53756859160b955b2e75b0eefe952189c184d7be30ecf7e858", - "sha256:068d3a33711fc4d93659c825a04480ff5a3854e1d78632cdc8f37fee917e8a60", - "sha256:08332c22e03b651c8eb7bf5fc2de90044f3672f43403b3d9ac7e7e0f4f76495e", - "sha256:08d464aa72a9a13826946b4fb9094bb4b16554bbea2e069e20bd903289b6ced9", - "sha256:0e5fe345b2bc7d88587149ac11def1f629d2671c4c34f5df38aed0ba59dc37f8", - "sha256:166c0c52f6488b8538b2a9f3fbc6aad61a7261e170698779b371e81b45f0440d", - "sha256:177f2b60a058f92a3cec7a1786c9106c29eca8987ecdfb79ee88126e5f47fa31", - "sha256:181fb5f3dee78dae7fd7ec57d02e58f7936498d587c6b7c1c8049ef448c8d285", - "sha256:1a32c662e7df9226fd850f054a3ead0e4213a96a70b5ce37b2d26ba27004e013", - "sha256:1a8043a33d58bc9b30dfac90f75712134ca34733ec3d8267b1bd682afe7194f5", - "sha256:1c6bf35e9a8998d8339fd9a05ac4ce465a4d2a2956cc0d837b67c4642ed9e947", - "sha256:1d1f34c71371f0e034004a0b583284b45d233dd0b5f64a9125e16b8a01d15067", - "sha256:20d218ec2b6899d29d6895419a58b6e44cc5ff8f0cc29fac8d236a8978ab702e", - "sha256:210160816d5a36cf41f48f38473b6f70d7bcb4b0527bedf0889cc0b4c3bb07db", - "sha256:218bbb9b883596715fc9997bb42470bf9f21bb832c3b34c2bf744d6fa8f2bbba", - "sha256:23654ad162c02a5636f0cd520a0310902c4421aab1d91a0b667722a4937cc445", - "sha256:239ee093b1db877c9f8fe2d71331a97f3b9c7c0d3ab9f09c4851004a11f44b65", - "sha256:26987dac3752688c696c77c3576f951dbbdb8c57f0957a41fb6f933cf84c0b62", - "sha256:275f500b4d26f67b6ec05629a4600645231bd75e4ed42087a7c1801bff04f4b3", - "sha256:2a69c71b1ae98a8021a09a0b43363b0143b0ce74e7c0e83cacba691b62655fb8", - "sha256:2a9e9d1a27e51a0f69e761a3d581c3af46729ec1c988fa1f839e04743026ae35", - "sha256:2ab4c96d922e53670ce25fbb9b63d5ea972e244de4fa1dd97b590d9fd66aacef", - "sha256:2adb497ada13097f30e386e88c959c0fda855a5f6f98845710f5bb2c57e14f12", - "sha256:2c37e6b714200824c73ca6eaf007382de76f39466a46e97558b8dc4cf643cfbf", - "sha256:2c42e9b277513b81cf507e6121c7b432b3235f980cac04f39f435b7902857f91", - "sha256:2cb4ac1d8f6b65ec84ddfacd275079e89d9df7c92f95675ba96c4f790a64df6e", - "sha256:2d065059e75a798bc1933c293b68d04d79b586bb7f8c921e0ca1e82759d0dbb1", - "sha256:2f8c2eb0615e2e64ee27d478c7c13f51e5329d7972d9e15528d3e4cfc4a08f0d", - "sha256:30f23e6253c5f43a809dea02dc28a9f5fa747735dc819f10c073fe1b605e97d4", - "sha256:32f0d1f6243e90ee43bc6ee3e8c30ac5b09ca63f5dd35dbc985a1fc5208c451a", - "sha256:3467ab511bfe3360967d7dc53b49f272d59309e57a067dd2405b4d35e7dcf9dc", - "sha256:3daacc9a4e3f428a84dd56bf31f20b768eb0b204af891ed68e1f06db9edf546f", - "sha256:419010156b914a3e5da4e4adf992bee050924d0fe423c4b329e523e2c14c3547", - "sha256:43251d7f29a59120a26f5a0d9583b9e112999e500afabcfdcb91606d3c5c89e3", - "sha256:44d464bdc384874601a177375028012a5f177f1505279f9456fea84bbc575c7f", - "sha256:4b3e8aa8226d6560de8c2b9d5ff8555ea482599c670610758afdc97f3e021e9c", - "sha256:51bc8429d9376224cd3cf7e8ce4f208b4c930cd10e515b6ac6a72cbc3370f0d9", - "sha256:5512078d00263de6cb04e9d26c9ae17611098f52357fea856213e38dc462f81f", - "sha256:55c14c20be247b8a1aeaf3ab4476265e3ca83096bb8e09bb1a7aa806088def4f", - "sha256:56ad9776b65d8743f86698a1973292c966cf3abff627efc44ed60e66cc538ddd", - "sha256:57d216fab0b5c432aabf7170883d7c11671622bde8bd1436c46d633163a703f6", - "sha256:5c2308de665b7130cd0e40a2329278226e4cf083f7400c51ca7e19ccfb3886f3", - "sha256:5cf6c6f6193797372adf50c91d0171743d16299491c75acad8650107dffa9269", - "sha256:5fe3e9b705250d0172ed4e100a811543108653fb2b66b9e702a088ad03772a07", - "sha256:63144e36209ad8e4e65384dbf2d52dd5b1866986079c00a72335402a38aacdc5", - "sha256:65a4a6072436bf0a4825b1c295d248cc17e5f4651e60ee62427a5bcaa8622a7a", - "sha256:6a13a9caea485df164c51be4eb0c87f97f790b7c3213d635eba2314d959fe929", - "sha256:6b54bc4ca5f9b9bba8cd4fb91c24b2446a86b5ae7f8975cf3b7a277353c3127c", - "sha256:6ceed6247fc2d33b2a7b7d25d8a0fe645b68798856e0bc7a9800c5fd945eb80f", - "sha256:73fc9a0a4343188bdb421783e600bfaf81d0793cd4cce6bafb3c2ed567a74cd5", - "sha256:76897944cd9239e8a70955679b531b9a0619f76e25476e57ed373322d9c2075d", - "sha256:7915f0c60e4e6e65d90f136d85dd3b429ae9191c36b380e626064694563dbd9f", - "sha256:7bd5efc26b39f7fc82d4ab1d86a7f0644c8e34f3699c33f85bfa9a717a030e1b", - "sha256:7cabcf39c81e5b988d0adefdaea2eb9b4fd9bd62d5ed6559988c62f36bfa9a89", - "sha256:7d9b76322e49c056bcc819f8bdca37a2daa5a6d42c07f30927b501088db03309", - "sha256:7db7fdc2d71fd1444d85ca3f3d682ba2df7d61a637dfc6d80793f439eae264ab", - "sha256:8079486118919f600c603536e2490ca37b3dbd3280e3ad6eaacfe6264605ac8a", - "sha256:8359bef65f49d51476e9811d59c015f0ddae618ee0e44144f5595278c9f8268c", - "sha256:83c155b4a33368d9b9c2543e78f2452090fb030c52401ca608ef16fa58c98353", - "sha256:83d054818a8d1198d8bd8bc3ea2aac112a2c19def2bf73758321976788706398", - "sha256:87bf3f91a9328a941acc44eceffd4e1f5f89b030985b2966637e582157173b98", - "sha256:87df18fce4440477c3ef1fd7ae17c704a69a74a77e705a12be135ee0651a0c2d", - "sha256:87e9903b8668a16ef02c08ba4ebc91e57a49c481e9b5866e31d798632805014b", - "sha256:88a5ac3280232d4ed8e994cbc03b46a1807ce0aa123867b40c4a41f226c61f94", - "sha256:88f6fd5a5c1302ce79993cc5feeadcc795a70f953c762544d01fb02b2db4ea33", - "sha256:8d4f0eed76b430f009fbefca1a0028ddb112891b03cb556d7440d5cd68eb89a9", - "sha256:8db8f0c59c84792c12661f8efa85de160f80efe16b87a9d5de91b93f9e0bce3c", - "sha256:8e5b927acc5f2f59547270b0309a46d983edc44be64e1ca27a7fcb0474d6cd67", - "sha256:9353c2af2dd467333d4850a16edb66855e795561cd170685178f706c80d2c71e", - "sha256:949aaa1118660f992dbf0968487b3e3cfdad67f948658ab08c6b5762e90cc8b6", - "sha256:9850754c434e636ce3dc586f534bb23bcbd78940c304775bee9005bf610e98f1", - "sha256:9d625692578dd40a112df30c02a1adf068027566abd8e6a74893bb13d441c150", - "sha256:9f1a3e01dce3cd54060791e7e24588417c98b941baa5974700eeb0b8eb65b0a0", - "sha256:9fdcb80f4e9fbb33b58e9bf95e7dbbedff505d1bcd1c05f7c7ce883632710006", - "sha256:a2c28c6487f17d8db0089e8b2cdc13de859366b94cc6cdc50e1b0a4147b56551", - "sha256:a4b8617499b2371c7353302c5116a7e0a3a12da66389ce53140e607d3bf7b3d3", - "sha256:a51d0ddd4deb8871c6de15a772ef40b3dbd26a3c0451bb9e66bc76fc5a784e5b", - "sha256:a9c421153aa23c323bd8483d4155b4eee82c9a50ac11cccd83539104a8279c64", - "sha256:a9d752c97f6bbe327352f76e5b86442d776abc789249fc5e72eacb49e6916482", - "sha256:b96c3d9266439d17f35fc2173111d93afc1162f168e95aed122c1ca517b1f8f1", - "sha256:baec5675944b4a47749c93c01c73d826ef7d42d36ba8d0dba36336fa80c76426", - "sha256:bb1ed4fcb0b3c2f3ea2c5767434622fe5d660e5752f21ac2e8d737b1e5e480bb", - "sha256:bb62841e839ee992c37bb75e75891c7f4904e772db3691c59daaca5b4ab960e1", - "sha256:bbaa31f2cb49013818bde319232ccd72da62ee40f7d2aa532083eda5664e85ff", - "sha256:bd574145d930cf9405a64f9923600879a5ce51d9f315443a5f706374841327b6", - "sha256:c05270b290acd8d249739f40d272a64dd597d5a4b90f27d830e538bc2549303c", - "sha256:c0cea44bba5c5601b297bc8307e4075535b95163402e4906b2e9b82788a2a6df", - "sha256:c11a4ab7debc456326a2bac67f35ee0ac792bcf812c7562a4a28559a5c795e27", - "sha256:c329a4dcc395364a1c0d2d1574d725fe81a840783dda64c31c5a60fc7d41472c", - "sha256:c6280f5aeafa1731f0a3709463ab33d8e0624321593951aefada5472f0b313fd", - "sha256:ca1a209157f242eb183e209040097118472e169f2e069bfbd40c303e24866543", - "sha256:cfc1fc38e37630dd12d519bdec9dcd4b345aec9930bb9ce0ed04461f49e58b52", - "sha256:d468cffb82d90789696d5b4d8b6ab8843052cba58a15296691a7a3df55143cd2", - "sha256:d52f5d0615ea83fd853d4e1d8acf93cc2e0223ad4568ba1e1f6ca72e94ea7b9d", - "sha256:df81e3407630de060ae8313da49509c3caa33b1a9415562284eaf3d0c7705f9f", - "sha256:e06a9ebc8656e030ccfe44634f2a541b4b1801cd52e390a53ad8bacbd65f8518", - "sha256:e4a0f374200e8443d9746e947ebb346c40f83a3970e75a685ade0adbba5c48d9", - "sha256:e5c9d86d9b13b18aafa88303e2cd21e677f5da2a14c828d2c460fe513af2e9a5", - "sha256:eb276a53717f2bcfb6df0bcf284d8a12069002508d4c1ca715799226024ccd45", - "sha256:ee9622e84fe6e4cd4f020e5fda70d6206feff3157731df7151d457fdae18e541", - "sha256:ef73df487b7c14b477016947c92708c2d929e1dee2bacdd6fff5a82ed4539537", - "sha256:f15117b96866401825f3e94543145028a2947d19974429246ce59403f49e77c6", - "sha256:f6784eed29f9e036acb0b7769d9e78a0dc2c72c2d8ba7903005350d817e287a4", - "sha256:f75698c5c5c542417ac4956acfc420f7d4a2396adca63a015fd66641ea751759", - "sha256:fb7b54830cee8cf9923d969e2df87ce20e625b1af2fd194222ab902d3adcc29c" - ], - "markers": "python_version >= '3.7'", - "version": "==0.4.4" - }, - "scikit-learn": { - "hashes": [ - "sha256:0828673c5b520e879f2af6a9e99eee0eefea69a2188be1ca68a6121b809055c1", - "sha256:0ea5d40c0e3951df445721927448755d3fe1d80833b0b7308ebff5d2a45e6414", - "sha256:10e49170691514a94bb2e03787aa921b82dbc507a4ea1f20fd95557862c98dc1", - "sha256:154297ee43c0b83af12464adeab378dee2d0a700ccd03979e2b821e7dd7cc1c2", - "sha256:161808750c267b77b4a9603cf9c93579c7a74ba8486b1336034c2f1579546d21", - "sha256:1bd8d3a19d4bd6dc5a7d4f358c8c3a60934dc058f363c34c0ac1e9e12a31421d", - "sha256:1ff4ba34c2abff5ec59c803ed1d97d61b036f659a17f55be102679e88f926fac", - "sha256:508907e5f81390e16d754e8815f7497e52139162fd69c4fdbd2dfa5d6cc88915", - "sha256:5944ce1faada31c55fb2ba20a5346b88e36811aab504ccafb9f0339e9f780395", - "sha256:5f57428de0c900a98389c4a433d4a3cf89de979b3aa24d1c1d251802aa15e44d", - "sha256:689b6f74b2c880276e365fe84fe4f1befd6a774f016339c65655eaff12e10cbf", - "sha256:781586c414f8cc58e71da4f3d7af311e0505a683e112f2f62919e3019abd3745", - "sha256:7b073a27797a283187a4ef4ee149959defc350b46cbf63a84d8514fe16b69855", - "sha256:88e0672c7ac21eb149d409c74cc29f1d611d5158175846e7a9c2427bd12b3956", - "sha256:909144d50f367a513cee6090873ae582dba019cb3fca063b38054fa42704c3a4", - "sha256:97625f217c5c0c5d0505fa2af28ae424bd37949bb2f16ace3ff5f2f81fb4498b", - "sha256:9a07f90846313a7639af6a019d849ff72baadfa4c74c778821ae0fad07b7275b", - "sha256:b59e3e62d2be870e5c74af4e793293753565c7383ae82943b83383fdcf5cc5c1", - "sha256:b5e865e9bd59396220de49cb4a57b17016256637c61b4c5cc81aaf16bc123bbe", - "sha256:da3f404e9e284d2b0a157e1b56b6566a34eb2798205cba35a211df3296ab7a74", - "sha256:f5b213bc29cc30a89a3130393b0e39c847a15d769d6e59539cd86b75d276b1a7" - ], - "markers": "python_version >= '3.9'", - "version": "==1.5.1" - }, - "scipy": { - "hashes": [ - "sha256:0c2f95de3b04e26f5f3ad5bb05e74ba7f68b837133a4492414b3afd79dfe540e", - "sha256:1729560c906963fc8389f6aac023739ff3983e727b1a4d87696b7bf108316a79", - "sha256:278266012eb69f4a720827bdd2dc54b2271c97d84255b2faaa8f161a158c3b37", - "sha256:2843f2d527d9eebec9a43e6b406fb7266f3af25a751aa91d62ff416f54170bc5", - "sha256:2da0469a4ef0ecd3693761acbdc20f2fdeafb69e6819cc081308cc978153c675", - "sha256:2ff0a7e01e422c15739ecd64432743cf7aae2b03f3084288f399affcefe5222d", - "sha256:2ff38e22128e6c03ff73b6bb0f85f897d2362f8c052e3b8ad00532198fbdae3f", - "sha256:30ac8812c1d2aab7131a79ba62933a2a76f582d5dbbc695192453dae67ad6310", - "sha256:3a1b111fac6baec1c1d92f27e76511c9e7218f1695d61b59e05e0fe04dc59617", - "sha256:4079b90df244709e675cdc8b93bfd8a395d59af40b72e339c2287c91860deb8e", - "sha256:5149e3fd2d686e42144a093b206aef01932a0059c2a33ddfa67f5f035bdfe13e", - "sha256:5a275584e726026a5699459aa72f828a610821006228e841b94275c4a7c08417", - "sha256:631f07b3734d34aced009aaf6fedfd0eb3498a97e581c3b1e5f14a04164a456d", - "sha256:716e389b694c4bb564b4fc0c51bc84d381735e0d39d3f26ec1af2556ec6aad94", - "sha256:8426251ad1e4ad903a4514712d2fa8fdd5382c978010d1c6f5f37ef286a713ad", - "sha256:8475230e55549ab3f207bff11ebfc91c805dc3463ef62eda3ccf593254524ce8", - "sha256:8bddf15838ba768bb5f5083c1ea012d64c9a444e16192762bd858f1e126196d0", - "sha256:8e32dced201274bf96899e6491d9ba3e9a5f6b336708656466ad0522d8528f69", - "sha256:8f9ea80f2e65bdaa0b7627fb00cbeb2daf163caa015e59b7516395fe3bd1e066", - "sha256:97c5dddd5932bd2a1a31c927ba5e1463a53b87ca96b5c9bdf5dfd6096e27efc3", - "sha256:a49f6ed96f83966f576b33a44257d869756df6cf1ef4934f59dd58b25e0327e5", - "sha256:af29a935803cc707ab2ed7791c44288a682f9c8107bc00f0eccc4f92c08d6e07", - "sha256:b05d43735bb2f07d689f56f7b474788a13ed8adc484a85aa65c0fd931cf9ccd2", - "sha256:b28d2ca4add7ac16ae8bb6632a3c86e4b9e4d52d3e34267f6e1b0c1f8d87e389", - "sha256:b99722ea48b7ea25e8e015e8341ae74624f72e5f21fc2abd45f3a93266de4c5d", - "sha256:baff393942b550823bfce952bb62270ee17504d02a1801d7fd0719534dfb9c84", - "sha256:c0ee987efa6737242745f347835da2cc5bb9f1b42996a4d97d5c7ff7928cb6f2", - "sha256:d0d2821003174de06b69e58cef2316a6622b60ee613121199cb2852a873f8cf3", - "sha256:e0cf28db0f24a38b2a0ca33a85a54852586e43cf6fd876365c86e0657cfe7d73", - "sha256:e4f5a7c49323533f9103d4dacf4e4f07078f360743dec7f7596949149efeec06", - "sha256:eb58ca0abd96911932f688528977858681a59d61a7ce908ffd355957f7025cfc", - "sha256:edaf02b82cd7639db00dbff629995ef185c8df4c3ffa71a5562a595765a06ce1", - "sha256:fef8c87f8abfb884dac04e97824b61299880c43f4ce675dd2cbeadd3c9b466d2" - ], - "markers": "python_version >= '3.10'", - "version": "==1.14.1" - }, - "sentence-transformers": { - "hashes": [ - "sha256:01050cc4053c49b9f5b78f6980b5a72db3fd3a0abb9169b1792ac83875505ee6", - "sha256:8a3d2c537cc4d1014ccc20ac92be3d6135420a3bc60ae29a3a8a9b4bb35fbff6" - ], - "markers": "python_full_version >= '3.8.0'", - "version": "==3.0.1" + "version": "==0.10.3" }, "setuptools": { "hashes": [ - "sha256:b208925fcb9f7af924ed2dc04708ea89791e24bde0d3020b27df0e116088b34e", - "sha256:d59a3e788ab7e012ab2c4baed1b376da6366883ee20d7a5fc426816e3d7b1193" + "sha256:35ab7fd3bcd95e6b7fd704e4a1539513edad446c097797f2985e0e4b960772f2", + "sha256:d59a21b17a275fb872a9c3dae73963160ae079f1049ed956880cd7c09b120538" ], "markers": "python_version >= '3.8'", - "version": "==73.0.1" + "version": "==75.1.0" }, "six": { "hashes": [ @@ -2393,203 +1592,13 @@ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==1.16.0" }, - "sympy": { - "hashes": [ - "sha256:401449d84d07be9d0c7a46a64bd54fe097667d5e7181bfe67ec777be9e01cb13", - "sha256:c51d75517712f1aed280d4ce58506a4a88d635d6b5dd48b39102a7ae1f3fcfe9" - ], - "markers": "python_version >= '3.8'", - "version": "==1.13.2" - }, - "textdistance": { - "hashes": [ - "sha256:0cb1b2cc8e3339ddc3e0f8c870e49fb49de6ecc42a718917308b3c971f34aa56", - "sha256:d6dabc50b4ea832cdcf0e1e6021bd0c7fcd9ade155888d79bb6a3c31fce2dc6f" - ], - "index": "pypi", - "markers": "python_version >= '3.5'", - "version": "==4.6.3" - }, - "threadpoolctl": { - "hashes": [ - "sha256:082433502dd922bf738de0d8bcc4fdcbf0979ff44c42bd40f5af8a282f6fa107", - "sha256:56c1e26c150397e58c4926da8eeee87533b1e32bef131bd4bf6a2f45f3185467" - ], - "markers": "python_version >= '3.8'", - "version": "==3.5.0" - }, "tinydb": { "hashes": [ - "sha256:30c06d12383d7c332e404ca6a6103fb2b32cbf25712689648c39d9a6bd34bd3d", - "sha256:6dd686a9c5a75dfa9280088fd79a419aefe19cd7f4bd85eba203540ef856d564" - ], - "markers": "python_version >= '3.7' and python_version < '4.0'", - "version": "==4.8.0" - }, - "tokenizers": { - "hashes": [ - "sha256:01d62812454c188306755c94755465505836fd616f75067abcae529c35edeb57", - "sha256:02e81bf089ebf0e7f4df34fa0207519f07e66d8491d963618252f2e0729e0b46", - "sha256:04ce49e82d100594715ac1b2ce87d1a36e61891a91de774755f743babcd0dd52", - "sha256:07f9295349bbbcedae8cefdbcfa7f686aa420be8aca5d4f7d1ae6016c128c0c5", - "sha256:08a44864e42fa6d7d76d7be4bec62c9982f6f6248b4aa42f7302aa01e0abfd26", - "sha256:0b5ca92bfa717759c052e345770792d02d1f43b06f9e790ca0a1db62838816f3", - "sha256:0b9394bd204842a2a1fd37fe29935353742be4a3460b6ccbaefa93f58a8df43d", - "sha256:0bcce02bf1ad9882345b34d5bd25ed4949a480cf0e656bbd468f4d8986f7a3f1", - "sha256:0e64bfde9a723274e9a71630c3e9494ed7b4c0f76a1faacf7fe294cd26f7ae7c", - "sha256:10a707cc6c4b6b183ec5dbfc5c34f3064e18cf62b4a938cb41699e33a99e03c1", - "sha256:16baac68651701364b0289979ecec728546133e8e8fe38f66fe48ad07996b88b", - "sha256:1de5bc8652252d9357a666e609cb1453d4f8e160eb1fb2830ee369dd658e8975", - "sha256:1f0360cbea28ea99944ac089c00de7b2e3e1c58f479fb8613b6d8d511ce98267", - "sha256:2e8a3dd055e515df7054378dc9d6fa8c8c34e1f32777fb9a01fea81496b3f9d3", - "sha256:3174c76efd9d08f836bfccaca7cfec3f4d1c0a4cf3acbc7236ad577cc423c840", - "sha256:35583cd46d16f07c054efd18b5d46af4a2f070a2dd0a47914e66f3ff5efb2b1e", - "sha256:39c1ec76ea1027438fafe16ecb0fb84795e62e9d643444c1090179e63808c69d", - "sha256:3b11853f17b54c2fe47742c56d8a33bf49ce31caf531e87ac0d7d13d327c9334", - "sha256:427c4f0f3df9109314d4f75b8d1f65d9477033e67ffaec4bca53293d3aca286d", - "sha256:43350270bfc16b06ad3f6f07eab21f089adb835544417afda0f83256a8bf8b75", - "sha256:453e4422efdfc9c6b6bf2eae00d5e323f263fff62b29a8c9cd526c5003f3f642", - "sha256:4692ab92f91b87769d950ca14dbb61f8a9ef36a62f94bad6c82cc84a51f76f6a", - "sha256:4ad23d37d68cf00d54af184586d79b84075ada495e7c5c0f601f051b162112dc", - "sha256:4f3fefdc0446b1a1e6d81cd4c07088ac015665d2e812f6dbba4a06267d1a2c95", - "sha256:56ae39d4036b753994476a1b935584071093b55c7a72e3b8288e68c313ca26e7", - "sha256:5c88d1481f1882c2e53e6bb06491e474e420d9ac7bdff172610c4f9ad3898059", - "sha256:61b7fe8886f2e104d4caf9218b157b106207e0f2a4905c9c7ac98890688aabeb", - "sha256:621d670e1b1c281a1c9698ed89451395d318802ff88d1fc1accff0867a06f153", - "sha256:6258c2ef6f06259f70a682491c78561d492e885adeaf9f64f5389f78aa49a051", - "sha256:6309271f57b397aa0aff0cbbe632ca9d70430839ca3178bf0f06f825924eca22", - "sha256:638e43936cc8b2cbb9f9d8dde0fe5e7e30766a3318d2342999ae27f68fdc9bd6", - "sha256:63c38f45d8f2a2ec0f3a20073cccb335b9f99f73b3c69483cd52ebc75369d8a1", - "sha256:670b802d4d82bbbb832ddb0d41df7015b3e549714c0e77f9bed3e74d42400fbe", - "sha256:6852c5b2a853b8b0ddc5993cd4f33bfffdca4fcc5d52f89dd4b8eada99379285", - "sha256:6b2da5c32ed869bebd990c9420df49813709e953674c0722ff471a116d97b22d", - "sha256:6c330c0eb815d212893c67a032e9dc1b38a803eccb32f3e8172c19cc69fbb439", - "sha256:6f8a20266e695ec9d7a946a019c1d5ca4eddb6613d4f466888eee04f16eedb85", - "sha256:706a37cc5332f85f26efbe2bdc9ef8a9b372b77e4645331a405073e4b3a8c1c6", - "sha256:71e3ec71f0e78780851fef28c2a9babe20270404c921b756d7c532d280349214", - "sha256:72791f9bb1ca78e3ae525d4782e85272c63faaef9940d92142aa3eb79f3407a3", - "sha256:76951121890fea8330d3a0df9a954b3f2a37e3ec20e5b0530e9a0044ca2e11fe", - "sha256:78e769eb3b2c79687d9cb0f89ef77223e8e279b75c0a968e637ca7043a84463f", - "sha256:7c9d5b6c0e7a1e979bec10ff960fae925e947aab95619a6fdb4c1d8ff3708ce3", - "sha256:7fb297edec6c6841ab2e4e8f357209519188e4a59b557ea4fafcf4691d1b4c98", - "sha256:7ff898780a155ea053f5d934925f3902be2ed1f4d916461e1a93019cc7250837", - "sha256:82c8b8063de6c0468f08e82c4e198763e7b97aabfe573fd4cf7b33930ca4df77", - "sha256:85aa3ab4b03d5e99fdd31660872249df5e855334b6c333e0bc13032ff4469c4a", - "sha256:89183e55fb86e61d848ff83753f64cded119f5d6e1f553d14ffee3700d0a4a49", - "sha256:8a6298bde623725ca31c9035a04bf2ef63208d266acd2bed8c2cb7d2b7d53ce6", - "sha256:8b01afb7193d47439f091cd8f070a1ced347ad0f9144952a30a41836902fe09e", - "sha256:952078130b3d101e05ecfc7fc3640282d74ed26bcf691400f872563fca15ac97", - "sha256:952b80dac1a6492170f8c2429bd11fcaa14377e097d12a1dbe0ef2fb2241e16c", - "sha256:9620b78e0b2d52ef07b0d428323fb34e8ea1219c5eac98c2596311f20f1f9266", - "sha256:9ed240c56b4403e22b9584ee37d87b8bfa14865134e3e1c3fb4b2c42fafd3256", - "sha256:a179856d1caee06577220ebcfa332af046d576fb73454b8f4d4b0ba8324423ea", - "sha256:a2b718f316b596f36e1dae097a7d5b91fc5b85e90bf08b01ff139bd8953b25af", - "sha256:ac11016d0a04aa6487b1513a3a36e7bee7eec0e5d30057c9c0408067345c48d2", - "sha256:ad57d59341710b94a7d9dbea13f5c1e7d76fd8d9bcd944a7a6ab0b0da6e0cc66", - "sha256:b07c538ba956843833fee1190cf769c60dc62e1cf934ed50d77d5502194d63b1", - "sha256:b279ab506ec4445166ac476fb4d3cc383accde1ea152998509a94d82547c8e2a", - "sha256:b2edbc75744235eea94d595a8b70fe279dd42f3296f76d5a86dde1d46e35f574", - "sha256:b342d2ce8fc8d00f376af068e3274e2e8649562e3bc6ae4a67784ded6b99428d", - "sha256:b4399b59d1af5645bcee2072a463318114c39b8547437a7c2d6a186a1b5a0e2d", - "sha256:b4c89aa46c269e4e70c4d4f9d6bc644fcc39bb409cb2a81227923404dd6f5227", - "sha256:b70bfbe3a82d3e3fb2a5e9b22a39f8d1740c96c68b6ace0086b39074f08ab89a", - "sha256:b82931fa619dbad979c0ee8e54dd5278acc418209cc897e42fac041f5366d626", - "sha256:bac0b0eb952412b0b196ca7a40e7dce4ed6f6926489313414010f2e6b9ec2adf", - "sha256:bb9dfe7dae85bc6119d705a76dc068c062b8b575abe3595e3c6276480e67e3f1", - "sha256:bcd266ae85c3d39df2f7e7d0e07f6c41a55e9a3123bb11f854412952deacd828", - "sha256:bea6f9947e9419c2fda21ae6c32871e3d398cba549b93f4a65a2d369662d9403", - "sha256:c27b99889bd58b7e301468c0838c5ed75e60c66df0d4db80c08f43462f82e0d3", - "sha256:c2a0d47a89b48d7daa241e004e71fb5a50533718897a4cd6235cb846d511a478", - "sha256:c5c2ff13d157afe413bf7e25789879dd463e5a4abfb529a2d8f8473d8042e28f", - "sha256:c85cf76561fbd01e0d9ea2d1cbe711a65400092bc52b5242b16cfd22e51f0c58", - "sha256:ca407133536f19bdec44b3da117ef0d12e43f6d4b56ac4c765f37eca501c7bda", - "sha256:cbf001afbbed111a79ca47d75941e9e5361297a87d186cbfc11ed45e30b5daba", - "sha256:ce05fde79d2bc2e46ac08aacbc142bead21614d937aac950be88dc79f9db9022", - "sha256:d16ff18907f4909dca9b076b9c2d899114dd6abceeb074eca0c93e2353f943aa", - "sha256:d26194ef6c13302f446d39972aaa36a1dda6450bc8949f5eb4c27f51191375bd", - "sha256:d8c5d59d7b59885eab559d5bc082b2985555a54cda04dda4c65528d90ad252ad", - "sha256:d924204a3dbe50b75630bd16f821ebda6a5f729928df30f582fb5aade90c818a", - "sha256:dadc509cc8a9fe460bd274c0e16ac4184d0958117cf026e0ea8b32b438171594", - "sha256:dd26e3afe8a7b61422df3176e06664503d3f5973b94f45d5c45987e1cb711876", - "sha256:ddf672ed719b4ed82b51499100f5417d7d9f6fb05a65e232249268f35de5ed14", - "sha256:dfedf31824ca4915b511b03441784ff640378191918264268e6923da48104acc", - "sha256:e28cab1582e0eec38b1f38c1c1fb2e56bce5dc180acb1724574fc5f47da2a4fe", - "sha256:e742d76ad84acbdb1a8e4694f915fe59ff6edc381c97d6dfdd054954e3478ad4", - "sha256:e83a31c9cf181a0a3ef0abad2b5f6b43399faf5da7e696196ddd110d332519ee", - "sha256:e8d1ed93beda54bbd6131a2cb363a576eac746d5c26ba5b7556bc6f964425594", - "sha256:e8ff5b90eabdcdaa19af697885f70fe0b714ce16709cf43d4952f1f85299e73a", - "sha256:ec11802450a2487cdf0e634b750a04cbdc1c4d066b97d94ce7dd2cb51ebb325b", - "sha256:ecb2651956eea2aa0a2d099434134b1b68f1c31f9a5084d6d53f08ed43d45ff2", - "sha256:ed69af290c2b65169f0ba9034d1dc39a5db9459b32f1dd8b5f3f32a3fcf06eab", - "sha256:eddd5783a4a6309ce23432353cdb36220e25cbb779bfa9122320666508b44b88", - "sha256:ee59e6680ed0fdbe6b724cf38bd70400a0c1dd623b07ac729087270caeac88e3", - "sha256:f03727225feaf340ceeb7e00604825addef622d551cbd46b7b775ac834c1e1c4", - "sha256:f3bbb7a0c5fcb692950b041ae11067ac54826204318922da754f908d95619fbc", - "sha256:f8a9c828277133af13f3859d1b6bf1c3cb6e9e1637df0e45312e6b7c2e622b1f", - "sha256:f97660f6c43efd3e0bfd3f2e3e5615bf215680bad6ee3d469df6454b8c6e8256", - "sha256:f9939ca7e58c2758c01b40324a59c034ce0cebad18e0d4563a9b1beab3018243" - ], - "markers": "python_version >= '3.7'", - "version": "==0.19.1" - }, - "torch": { - "hashes": [ - "sha256:2497cbc7b3c951d69b276ca51fe01c2865db67040ac67f5fc20b03e41d16ea4a", - "sha256:3374128bbf7e62cdaed6c237bfd39809fbcfaa576bee91e904706840c3f2195c", - "sha256:3af4de2a618fb065e78404c4ba27a818a7b7957eaeff28c6c66ce7fb504b68b8", - "sha256:4ed94583e244af51d6a8d28701ca5a9e02d1219e782f5a01dd401f90af17d8ac", - "sha256:618808d3f610d5f180e47a697d4ec90b810953bb1e020f424b2ac7fb0884b545", - "sha256:685418ab93730efbee71528821ff54005596970dd497bf03c89204fb7e3f71de", - "sha256:688eec9240f3ce775f22e1e1a5ab9894f3d5fe60f3f586deb7dbd23a46a83916", - "sha256:7334325c0292cbd5c2eac085f449bf57d3690932eac37027e193ba775703c9e6", - "sha256:8940fc8b97a4c61fdb5d46a368f21f4a3a562a17879e932eb51a5ec62310cb31", - "sha256:91aaf00bfe1ffa44dc5b52809d9a95129fca10212eca3ac26420eb11727c6288", - "sha256:97730014da4c57ffacb3c09298c6ce05400606e890bd7a05008d13dd086e46b1", - "sha256:997084a0f9784d2a89095a6dc67c7925e21bf25dea0b3d069b41195016ccfcbb", - "sha256:a046491aaf96d1215e65e1fa85911ef2ded6d49ea34c8df4d0638879f2402eef", - "sha256:a2feb98ac470109472fb10dfef38622a7ee08482a16c357863ebc7bc7db7c8f7", - "sha256:bc3988e8b36d1e8b998d143255d9408d8c75da4ab6dd0dcfd23b623dfb0f0f57", - "sha256:c4ca297b7bd58b506bfd6e78ffd14eb97c0e7797dcd7965df62f50bb575d8954", - "sha256:cc30457ea5489c62747d3306438af00c606b509d78822a88f804202ba63111ed", - "sha256:e743adadd8c8152bb8373543964551a7cb7cc20ba898dc8f9c0cdbe47c283de0", - "sha256:ed765d232d23566052ba83632ec73a4fccde00b4c94ad45d63b471b09d63b7a7", - "sha256:f169b4ea6dc93b3a33319611fcc47dc1406e4dd539844dcbd2dec4c1b96e166d" - ], - "index": "pypi", - "markers": "python_full_version >= '3.8.0'", - "version": "==2.4.0" - }, - "tqdm": { - "hashes": [ - "sha256:90279a3770753eafc9194a0364852159802111925aa30eb3f9d85b0e805ac7cd", - "sha256:e1020aef2e5096702d8a025ac7d16b1577279c9d63f8375b63083e9a5f0fcbad" - ], - "markers": "python_version >= '3.7'", - "version": "==4.66.5" - }, - "transformers": { - "hashes": [ - "sha256:3b9a1a07ca65c665c7bf6109b7da76182184d10bb58d9ab14e6892e7b9e073a2", - "sha256:bd2642da18b4e6d29b135c17650cd7ca8e874f2d092d2eddd3ed6b71a93a155c" + "sha256:f7dfc39b8d7fda7a1ca62a8dbb449ffd340a117c1206b68c50b1a481fb95181d", + "sha256:f97030ee5cbc91eeadd1d7af07ab0e48ceb04aa63d4a983adbaca4cba16e86c3" ], - "markers": "python_full_version >= '3.8.0'", - "version": "==4.44.1" - }, - "triton": { - "hashes": [ - "sha256:0d5e10de8c011adeb7c878c6ce0dd6073b14367749e34467f1cff2bde1b78253", - "sha256:34e509deb77f1c067d8640725ef00c5cbfcb2052a1a3cb6a6d343841f92624eb", - "sha256:39b052da883351fdf6be3d93cedae6db3b8e3988d3b09ed221bccecfa9612230", - "sha256:41004fb1ae9a53fcb3e970745feb87f0e3c94c6ce1ba86e95fa3b8537894bef7", - "sha256:5ce8520437c602fb633f1324cc3871c47bee3b67acf9756c1a66309b60e3216c", - "sha256:6e5727202f7078c56f91ff13ad0c1abab14a0e7f2c87e91b12b6f64f3e8ae609", - "sha256:bcbf3b1c48af6a28011a5c40a5b3b9b5330530c3827716b5fbf6d7adcc1e53e9", - "sha256:cd34f19a8582af96e6291d4afce25dac08cb2a5d218c599163761e8e0827208e", - "sha256:e1efef76935b2febc365bfadf74bcb65a6f959a9872e5bddf44cc9e0adce1e1a", - "sha256:e8903767951bf86ec960b4fe4e21bc970055afc65e9d57e916d79ae3c93665e3" - ], - "markers": "python_version < '3.13' and platform_system == 'Linux' and platform_machine == 'x86_64'", - "version": "==3.0.0" + "markers": "python_version >= '3.8' and python_version < '4.0'", + "version": "==4.8.2" }, "tuspy": { "hashes": [ @@ -2604,257 +1613,136 @@ "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8" ], - "markers": "python_version < '3.13'", + "markers": "python_version >= '3.8'", "version": "==4.12.2" }, "tzdata": { "hashes": [ - "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd", - "sha256:9068bc196136463f5245e51efda838afa15aaeca9903f49050dfa2679db4d252" + "sha256:7d85cc416e9382e69095b7bdf4afd9e3880418a2413feec7069d533d6b4e31cc", + "sha256:a48093786cdcde33cad18c2555e8532f34422074448fbc874186f0abd79565cd" ], "markers": "python_version >= '2'", - "version": "==2024.1" + "version": "==2024.2" }, "urllib3": { "hashes": [ - "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472", - "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168" + "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac", + "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9" ], - "markers": "python_version >= '3.10'", - "version": "==2.2.2" + "markers": "python_version >= '3.8'", + "version": "==2.2.3" }, "werkzeug": { "hashes": [ - "sha256:097e5bfda9f0aba8da6b8545146def481d06aa7d3266e7448e2cccf67dd8bd18", - "sha256:fc9645dc43e03e4d630d23143a04a7f947a9a3b5727cd535fdfe155a17cc48c8" + "sha256:02c9eb92b7d6c06f31a782811505d2157837cea66aaede3e217c7c27c039476c", + "sha256:34f2371506b250df4d4f84bfe7b0921e4762525762bbd936614909fe25cd7306" ], "markers": "python_version >= '3.8'", - "version": "==3.0.3" - }, - "xxhash": { - "hashes": [ - "sha256:02c2e816896dc6f85922ced60097bcf6f008dedfc5073dcba32f9c8dd786f3c1", - "sha256:0691bfcc4f9c656bcb96cc5db94b4d75980b9d5589f2e59de790091028580837", - "sha256:07fda5de378626e502b42b311b049848c2ef38784d0d67b6f30bb5008642f8eb", - "sha256:08424f6648526076e28fae6ea2806c0a7d504b9ef05ae61d196d571e5c879c84", - "sha256:0a80ad0ffd78bef9509eee27b4a29e56f5414b87fb01a888353e3d5bda7038bd", - "sha256:0adfbd36003d9f86c8c97110039f7539b379f28656a04097e7434d3eaf9aa131", - "sha256:0ec70a89be933ea49222fafc3999987d7899fc676f688dd12252509434636622", - "sha256:1030a39ba01b0c519b1a82f80e8802630d16ab95dc3f2b2386a0b5c8ed5cbb10", - "sha256:109b436096d0a2dd039c355fa3414160ec4d843dfecc64a14077332a00aeb7da", - "sha256:1308fa542bbdbf2fa85e9e66b1077eea3a88bef38ee8a06270b4298a7a62a166", - "sha256:1328f6d8cca2b86acb14104e381225a3d7b42c92c4b86ceae814e5c400dbb415", - "sha256:13de2b76c1835399b2e419a296d5b38dc4855385d9e96916299170085ef72f57", - "sha256:14470ace8bd3b5d51318782cd94e6f94431974f16cb3b8dc15d52f3b69df8e00", - "sha256:149b7914451eb154b3dfaa721315117ea1dac2cc55a01bfbd4df7c68c5dd683d", - "sha256:160e0c19ee500482ddfb5d5570a0415f565d8ae2b3fd69c5dcfce8a58107b1c3", - "sha256:2014c5b3ff15e64feecb6b713af12093f75b7926049e26a580e94dcad3c73d8c", - "sha256:2061188a1ba352fc699c82bff722f4baacb4b4b8b2f0c745d2001e56d0dfb514", - "sha256:220f3f896c6b8d0316f63f16c077d52c412619e475f9372333474ee15133a558", - "sha256:23241ff6423378a731d84864bf923a41649dc67b144debd1077f02e6249a0d54", - "sha256:25b5a51dc3dfb20a10833c8eee25903fd2e14059e9afcd329c9da20609a307b2", - "sha256:297595fe6138d4da2c8ce9e72a04d73e58725bb60f3a19048bc96ab2ff31c692", - "sha256:2b4154c00eb22e4d543f472cfca430e7962a0f1d0f3778334f2e08a7ba59363c", - "sha256:2e76e83efc7b443052dd1e585a76201e40b3411fe3da7af4fe434ec51b2f163b", - "sha256:30eb2efe6503c379b7ab99c81ba4a779748e3830241f032ab46bd182bf5873af", - "sha256:3171f693dbc2cef6477054a665dc255d996646b4023fe56cb4db80e26f4cc520", - "sha256:33513d6cc3ed3b559134fb307aae9bdd94d7e7c02907b37896a6c45ff9ce51bd", - "sha256:33eac61d0796ca0591f94548dcfe37bb193671e0c9bcf065789b5792f2eda644", - "sha256:37889a0d13b0b7d739cfc128b1c902f04e32de17b33d74b637ad42f1c55101f6", - "sha256:38c384c434021e4f62b8d9ba0bc9467e14d394893077e2c66d826243025e1f81", - "sha256:392f52ebbb932db566973693de48f15ce787cabd15cf6334e855ed22ea0be5b3", - "sha256:3dbbd9892c5ebffeca1ed620cf0ade13eb55a0d8c84e0751a6653adc6ac40d0c", - "sha256:3e5b5e16c5a480fe5f59f56c30abdeba09ffd75da8d13f6b9b6fd224d0b4d0a2", - "sha256:3ff2c0a34eae7df88c868be53a8dd56fbdf592109e21d4bfa092a27b0bf4a7bf", - "sha256:42eca420c8fa072cc1dd62597635d140e78e384a79bb4944f825fbef8bfeeef6", - "sha256:4811336f1ce11cac89dcbd18f3a25c527c16311709a89313c3acaf771def2d4b", - "sha256:4cc2d67fdb4d057730c75a64c5923abfa17775ae234a71b0200346bfb0a7f482", - "sha256:4e28503dccc7d32e0b9817aa0cbfc1f45f563b2c995b7a66c4c8a0d232e840c7", - "sha256:4e2febf914ace002132aa09169cc572e0d8959d0f305f93d5828c4836f9bc5a6", - "sha256:50ac2184ffb1b999e11e27c7e3e70cc1139047e7ebc1aa95ed12f4269abe98d4", - "sha256:531af8845aaadcadf951b7e0c1345c6b9c68a990eeb74ff9acd8501a0ad6a1c9", - "sha256:53a068fe70301ec30d868ece566ac90d873e3bb059cf83c32e76012c889b8637", - "sha256:586886c7e89cb9828bcd8a5686b12e161368e0064d040e225e72607b43858ba2", - "sha256:59aa1203de1cb96dbeab595ded0ad0c0056bb2245ae11fac11c0ceea861382b9", - "sha256:5a74f23335b9689b66eb6dbe2a931a88fcd7a4c2cc4b1cb0edba8ce381c7a1da", - "sha256:5d0d307d27099bb0cbeea7260eb39ed4fdb99c5542e21e94bb6fd29e49c57a23", - "sha256:5d2a01dcce81789cf4b12d478b5464632204f4c834dc2d064902ee27d2d1f0ee", - "sha256:5d3a10609c51da2a1c0ea0293fc3968ca0a18bd73838455b5bca3069d7f8e32b", - "sha256:5ed9ebc46f24cf91034544b26b131241b699edbfc99ec5e7f8f3d02d6eb7fba4", - "sha256:6027dcd885e21581e46d3c7f682cfb2b870942feeed58a21c29583512c3f09f8", - "sha256:602d339548d35a8579c6b013339fb34aee2df9b4e105f985443d2860e4d7ffaa", - "sha256:604253b2143e13218ff1ef0b59ce67f18b8bd1c4205d2ffda22b09b426386898", - "sha256:61a1ff00674879725b194695e17f23d3248998b843eb5e933007ca743310f793", - "sha256:61c722ed8d49ac9bc26c7071eeaa1f6ff24053d553146d5df031802deffd03da", - "sha256:63107013578c8a730419adc05608756c3fa640bdc6abe806c3123a49fb829f43", - "sha256:683b94dbd1ca67557850b86423318a2e323511648f9f3f7b1840408a02b9a48c", - "sha256:685c4f4e8c59837de103344eb1c8a3851f670309eb5c361f746805c5471b8c88", - "sha256:695735deeddfb35da1677dbc16a083445360e37ff46d8ac5c6fcd64917ff9ade", - "sha256:6e5f70f6dca1d3b09bccb7daf4e087075ff776e3da9ac870f86ca316736bb4aa", - "sha256:6e93a5ad22f434d7876665444a97e713a8f60b5b1a3521e8df11b98309bff833", - "sha256:6fa0b72f2423e2aa53077e54a61c28e181d23effeaafd73fcb9c494e60930c8e", - "sha256:70dabf941dede727cca579e8c205e61121afc9b28516752fd65724be1355cc90", - "sha256:74752ecaa544657d88b1d1c94ae68031e364a4d47005a90288f3bab3da3c970f", - "sha256:7a46e1d6d2817ba8024de44c4fd79913a90e5f7265434cef97026215b7d30df6", - "sha256:7c5d3e570ef46adaf93fc81b44aca6002b5a4d8ca11bd0580c07eac537f36680", - "sha256:7cb29a034301e2982df8b1fe6328a84f4b676106a13e9135a0d7e0c3e9f806da", - "sha256:7ccb800c9418e438b44b060a32adeb8393764da7441eb52aa2aa195448935306", - "sha256:7ce379bcaa9fcc00f19affa7773084dd09f5b59947b3fb47a1ceb0179f91aaa1", - "sha256:7f85e0108d51092bdda90672476c7d909c04ada6923c14ff9d913c4f7dc8a3bc", - "sha256:80babcc30e7a1a484eab952d76a4f4673ff601f54d5142c26826502740e70b43", - "sha256:82085c2abec437abebf457c1d12fccb30cc8b3774a0814872511f0f0562c768c", - "sha256:82b833d5563fefd6fceafb1aed2f3f3ebe19f84760fdd289f8b926731c2e6e91", - "sha256:84f2caddf951c9cbf8dc2e22a89d4ccf5d86391ac6418fe81e3c67d0cf60b45f", - "sha256:893074d651cf25c1cc14e3bea4fceefd67f2921b1bb8e40fcfeba56820de80c6", - "sha256:89997aa1c4b6a5b1e5b588979d1da048a3c6f15e55c11d117a56b75c84531f5a", - "sha256:89e66ceed67b213dec5a773e2f7a9e8c58f64daeb38c7859d8815d2c89f39ad7", - "sha256:8d47ebd9f5d9607fd039c1fbf4994e3b071ea23eff42f4ecef246ab2b7334198", - "sha256:924361811732ddad75ff23e90efd9ccfda4f664132feecb90895bade6a1b4623", - "sha256:963be41bcd49f53af6d795f65c0da9b4cc518c0dd9c47145c98f61cb464f4839", - "sha256:97a662338797c660178e682f3bc180277b9569a59abfb5925e8620fba00b9fc5", - "sha256:9bed5144c6923cc902cd14bb8963f2d5e034def4486ab0bbe1f58f03f042f9a9", - "sha256:9c770750cc80e8694492244bca7251385188bc5597b6a39d98a9f30e8da984e0", - "sha256:9d32a592cac88d18cc09a89172e1c32d7f2a6e516c3dfde1b9adb90ab5df54a6", - "sha256:a5bc08f33c4966f4eb6590d6ff3ceae76151ad744576b5fc6c4ba8edd459fdec", - "sha256:a606c8070ada8aa2a88e181773fa1ef17ba65ce5dd168b9d08038e2a61b33754", - "sha256:a6c50017518329ed65a9e4829154626f008916d36295b6a3ba336e2458824c8c", - "sha256:a7b1d8315d9b5e9f89eb2933b73afae6ec9597a258d52190944437158b49d38e", - "sha256:a8fb786fb754ef6ff8c120cb96629fb518f8eb5a61a16aac3a979a9dbd40a084", - "sha256:a905ad00ad1e1c34fe4e9d7c1d949ab09c6fa90c919860c1534ff479f40fd12d", - "sha256:a9d360a792cbcce2fe7b66b8d51274ec297c53cbc423401480e53b26161a290d", - "sha256:b150b8467852e1bd844387459aa6fbe11d7f38b56e901f9f3b3e6aba0d660240", - "sha256:b702f806693201ad6c0a05ddbbe4c8f359626d0b3305f766077d51388a6bac58", - "sha256:b96d559e0fcddd3343c510a0fe2b127fbff16bf346dd76280b82292567523442", - "sha256:bcd51708a633410737111e998ceb3b45d3dbc98c0931f743d9bb0a209033a326", - "sha256:bfc8cdd7f33d57f0468b0614ae634cc38ab9202c6957a60e31d285a71ebe0301", - "sha256:c0342aafd421795d740e514bc9858ebddfc705a75a8c5046ac56d85fe97bf196", - "sha256:c279f0d2b34ef15f922b77966640ade58b4ccdfef1c4d94b20f2a364617a493f", - "sha256:c28b2fdcee797e1c1961cd3bcd3d545cab22ad202c846235197935e1df2f8ef7", - "sha256:c3bc7bf8cb8806f8d1c9bf149c18708cb1c406520097d6b0a73977460ea03602", - "sha256:c4dcb4120d0cc3cc448624147dba64e9021b278c63e34a38789b688fd0da9bf3", - "sha256:c8aa771ff2c13dd9cda8166d685d7333d389fae30a4d2bb39d63ab5775de8606", - "sha256:cc1276d369452040cbb943300dc8abeedab14245ea44056a2943183822513a18", - "sha256:cd2fd827b0ba763ac919440042302315c564fdb797294d86e8cdd4578e3bc7f3", - "sha256:d30bbc1644f726b825b3278764240f449d75f1a8bdda892e641d4a688b1494ae", - "sha256:d5e9db7ef3ecbfc0b4733579cea45713a76852b002cf605420b12ef3ef1ec148", - "sha256:dbd2ecfbfee70bc1a4acb7461fa6af7748ec2ab08ac0fa298f281c51518f982c", - "sha256:dd86b8e7f703ec6ff4f351cfdb9f428955859537125904aa8c963604f2e9d3e7", - "sha256:dee1316133c9b463aa81aca676bc506d3f80d8f65aeb0bba2b78d0b30c51d7bd", - "sha256:e0c48b6300cd0b0106bf49169c3e0536408dfbeb1ccb53180068a18b03c662ab", - "sha256:e5d0ddaca65ecca9c10dcf01730165fd858533d0be84c75c327487c37a906a27", - "sha256:e6a4dd644d72ab316b580a1c120b375890e4c52ec392d4aef3c63361ec4d77d1", - "sha256:eade977f5c96c677035ff39c56ac74d851b1cca7d607ab3d8f23c6b859379cab", - "sha256:ec28adb204b759306a3d64358a5e5c07d7b1dd0ccbce04aa76cb9377b7b70296", - "sha256:ece616532c499ee9afbb83078b1b952beffef121d989841f7f4b3dc5ac0fd212", - "sha256:eefc37f6138f522e771ac6db71a6d4838ec7933939676f3753eafd7d3f4c40bc", - "sha256:f0b48edbebea1b7421a9c687c304f7b44d0677c46498a046079d445454504737", - "sha256:f1abffa122452481a61c3551ab3c89d72238e279e517705b8b03847b1d93d738", - "sha256:f2f2c61bee5844d41c3eb015ac652a0229e901074951ae48581d58bfb2ba01be", - "sha256:f7b58d1fd3551b8c80a971199543379be1cee3d0d409e1f6d8b01c1a2eebf1f8", - "sha256:fa0cafd3a2af231b4e113fba24a65d7922af91aeb23774a8b78228e6cd785e3e", - "sha256:fa9f547bd98f5553d03160967866a71056a60960be00356a15ecc44efb40ba8e", - "sha256:fab81ef75003eda96239a23eda4e4543cedc22e34c373edcaf744e721a163986", - "sha256:fd1b2281d01723f076df3c8188f43f2472248a6b63118b036e641243656b1b0f", - "sha256:fe1a92cfbaa0a1253e339ccec42dbe6db262615e52df591b68726ab10338003f" - ], - "markers": "python_version >= '3.7'", - "version": "==3.5.0" + "version": "==3.0.4" }, "yarl": { "hashes": [ - "sha256:008d3e808d03ef28542372d01057fd09168419cdc8f848efe2804f894ae03e51", - "sha256:03caa9507d3d3c83bca08650678e25364e1843b484f19986a527630ca376ecce", - "sha256:07574b007ee20e5c375a8fe4a0789fad26db905f9813be0f9fef5a68080de559", - "sha256:09efe4615ada057ba2d30df871d2f668af661e971dfeedf0c159927d48bbeff0", - "sha256:0d2454f0aef65ea81037759be5ca9947539667eecebca092733b2eb43c965a81", - "sha256:0e9d124c191d5b881060a9e5060627694c3bdd1fe24c5eecc8d5d7d0eb6faabc", - "sha256:18580f672e44ce1238b82f7fb87d727c4a131f3a9d33a5e0e82b793362bf18b4", - "sha256:1f23e4fe1e8794f74b6027d7cf19dc25f8b63af1483d91d595d4a07eca1fb26c", - "sha256:206a55215e6d05dbc6c98ce598a59e6fbd0c493e2de4ea6cc2f4934d5a18d130", - "sha256:23d32a2594cb5d565d358a92e151315d1b2268bc10f4610d098f96b147370136", - "sha256:26a1dc6285e03f3cc9e839a2da83bcbf31dcb0d004c72d0730e755b33466c30e", - "sha256:29e0f83f37610f173eb7e7b5562dd71467993495e568e708d99e9d1944f561ec", - "sha256:2b134fd795e2322b7684155b7855cc99409d10b2e408056db2b93b51a52accc7", - "sha256:2d47552b6e52c3319fede1b60b3de120fe83bde9b7bddad11a69fb0af7db32f1", - "sha256:357495293086c5b6d34ca9616a43d329317feab7917518bc97a08f9e55648455", - "sha256:35a2b9396879ce32754bd457d31a51ff0a9d426fd9e0e3c33394bf4b9036b099", - "sha256:3777ce5536d17989c91696db1d459574e9a9bd37660ea7ee4d3344579bb6f129", - "sha256:3986b6f41ad22988e53d5778f91855dc0399b043fc8946d4f2e68af22ee9ff10", - "sha256:44d8ffbb9c06e5a7f529f38f53eda23e50d1ed33c6c869e01481d3fafa6b8142", - "sha256:49a180c2e0743d5d6e0b4d1a9e5f633c62eca3f8a86ba5dd3c471060e352ca98", - "sha256:4aa9741085f635934f3a2583e16fcf62ba835719a8b2b28fb2917bb0537c1dfa", - "sha256:4b21516d181cd77ebd06ce160ef8cc2a5e9ad35fb1c5930882baff5ac865eee7", - "sha256:4b3c1ffe10069f655ea2d731808e76e0f452fc6c749bea04781daf18e6039525", - "sha256:4c7d56b293cc071e82532f70adcbd8b61909eec973ae9d2d1f9b233f3d943f2c", - "sha256:4e9035df8d0880b2f1c7f5031f33f69e071dfe72ee9310cfc76f7b605958ceb9", - "sha256:54525ae423d7b7a8ee81ba189f131054defdb122cde31ff17477951464c1691c", - "sha256:549d19c84c55d11687ddbd47eeb348a89df9cb30e1993f1b128f4685cd0ebbf8", - "sha256:54beabb809ffcacbd9d28ac57b0db46e42a6e341a030293fb3185c409e626b8b", - "sha256:566db86717cf8080b99b58b083b773a908ae40f06681e87e589a976faf8246bf", - "sha256:5a2e2433eb9344a163aced6a5f6c9222c0786e5a9e9cac2c89f0b28433f56e23", - "sha256:5aef935237d60a51a62b86249839b51345f47564208c6ee615ed2a40878dccdd", - "sha256:604f31d97fa493083ea21bd9b92c419012531c4e17ea6da0f65cacdcf5d0bd27", - "sha256:63b20738b5aac74e239622d2fe30df4fca4942a86e31bf47a81a0e94c14df94f", - "sha256:686a0c2f85f83463272ddffd4deb5e591c98aac1897d65e92319f729c320eece", - "sha256:6a962e04b8f91f8c4e5917e518d17958e3bdee71fd1d8b88cdce74dd0ebbf434", - "sha256:6ad6d10ed9b67a382b45f29ea028f92d25bc0bc1daf6c5b801b90b5aa70fb9ec", - "sha256:6f5cb257bc2ec58f437da2b37a8cd48f666db96d47b8a3115c29f316313654ff", - "sha256:6fe79f998a4052d79e1c30eeb7d6c1c1056ad33300f682465e1b4e9b5a188b78", - "sha256:7855426dfbddac81896b6e533ebefc0af2f132d4a47340cee6d22cac7190022d", - "sha256:7d5aaac37d19b2904bb9dfe12cdb08c8443e7ba7d2852894ad448d4b8f442863", - "sha256:801e9264d19643548651b9db361ce3287176671fb0117f96b5ac0ee1c3530d53", - "sha256:81eb57278deb6098a5b62e88ad8281b2ba09f2f1147c4767522353eaa6260b31", - "sha256:824d6c50492add5da9374875ce72db7a0733b29c2394890aef23d533106e2b15", - "sha256:8397a3817d7dcdd14bb266283cd1d6fc7264a48c186b986f32e86d86d35fbac5", - "sha256:848cd2a1df56ddbffeb375535fb62c9d1645dde33ca4d51341378b3f5954429b", - "sha256:84fc30f71689d7fc9168b92788abc977dc8cefa806909565fc2951d02f6b7d57", - "sha256:8619d6915b3b0b34420cf9b2bb6d81ef59d984cb0fde7544e9ece32b4b3043c3", - "sha256:8a854227cf581330ffa2c4824d96e52ee621dd571078a252c25e3a3b3d94a1b1", - "sha256:8be9e837ea9113676e5754b43b940b50cce76d9ed7d2461df1af39a8ee674d9f", - "sha256:928cecb0ef9d5a7946eb6ff58417ad2fe9375762382f1bf5c55e61645f2c43ad", - "sha256:957b4774373cf6f709359e5c8c4a0af9f6d7875db657adb0feaf8d6cb3c3964c", - "sha256:992f18e0ea248ee03b5a6e8b3b4738850ae7dbb172cc41c966462801cbf62cf7", - "sha256:9fc5fc1eeb029757349ad26bbc5880557389a03fa6ada41703db5e068881e5f2", - "sha256:a00862fb23195b6b8322f7d781b0dc1d82cb3bcac346d1e38689370cc1cc398b", - "sha256:a3a6ed1d525bfb91b3fc9b690c5a21bb52de28c018530ad85093cc488bee2dd2", - "sha256:a6327976c7c2f4ee6816eff196e25385ccc02cb81427952414a64811037bbc8b", - "sha256:a7409f968456111140c1c95301cadf071bd30a81cbd7ab829169fb9e3d72eae9", - "sha256:a825ec844298c791fd28ed14ed1bffc56a98d15b8c58a20e0e08c1f5f2bea1be", - "sha256:a8c1df72eb746f4136fe9a2e72b0c9dc1da1cbd23b5372f94b5820ff8ae30e0e", - "sha256:a9bd00dc3bc395a662900f33f74feb3e757429e545d831eef5bb280252631984", - "sha256:aa102d6d280a5455ad6a0f9e6d769989638718e938a6a0a2ff3f4a7ff8c62cc4", - "sha256:aaaea1e536f98754a6e5c56091baa1b6ce2f2700cc4a00b0d49eca8dea471074", - "sha256:ad4d7a90a92e528aadf4965d685c17dacff3df282db1121136c382dc0b6014d2", - "sha256:b8477c1ee4bd47c57d49621a062121c3023609f7a13b8a46953eb6c9716ca392", - "sha256:ba6f52cbc7809cd8d74604cce9c14868306ae4aa0282016b641c661f981a6e91", - "sha256:bac8d525a8dbc2a1507ec731d2867025d11ceadcb4dd421423a5d42c56818541", - "sha256:bef596fdaa8f26e3d66af846bbe77057237cb6e8efff8cd7cc8dff9a62278bbf", - "sha256:c0ec0ed476f77db9fb29bca17f0a8fcc7bc97ad4c6c1d8959c507decb22e8572", - "sha256:c38c9ddb6103ceae4e4498f9c08fac9b590c5c71b0370f98714768e22ac6fa66", - "sha256:c7224cab95645c7ab53791022ae77a4509472613e839dab722a72abe5a684575", - "sha256:c74018551e31269d56fab81a728f683667e7c28c04e807ba08f8c9e3bba32f14", - "sha256:ca06675212f94e7a610e85ca36948bb8fc023e458dd6c63ef71abfd482481aa5", - "sha256:d1d2532b340b692880261c15aee4dc94dd22ca5d61b9db9a8a361953d36410b1", - "sha256:d25039a474c4c72a5ad4b52495056f843a7ff07b632c1b92ea9043a3d9950f6e", - "sha256:d5ff2c858f5f6a42c2a8e751100f237c5e869cbde669a724f2062d4c4ef93551", - "sha256:d7d7f7de27b8944f1fee2c26a88b4dabc2409d2fea7a9ed3df79b67277644e17", - "sha256:d7eeb6d22331e2fd42fce928a81c697c9ee2d51400bd1a28803965883e13cead", - "sha256:d8a1c6c0be645c745a081c192e747c5de06e944a0d21245f4cf7c05e457c36e0", - "sha256:d8b889777de69897406c9fb0b76cdf2fd0f31267861ae7501d93003d55f54fbe", - "sha256:d9e09c9d74f4566e905a0b8fa668c58109f7624db96a2171f21747abc7524234", - "sha256:db8e58b9d79200c76956cefd14d5c90af54416ff5353c5bfd7cbe58818e26ef0", - "sha256:ddb2a5c08a4eaaba605340fdee8fc08e406c56617566d9643ad8bf6852778fc7", - "sha256:e0381b4ce23ff92f8170080c97678040fc5b08da85e9e292292aba67fdac6c34", - "sha256:e23a6d84d9d1738dbc6e38167776107e63307dfc8ad108e580548d1f2c587f42", - "sha256:e516dc8baf7b380e6c1c26792610230f37147bb754d6426462ab115a02944385", - "sha256:ea65804b5dc88dacd4a40279af0cdadcfe74b3e5b4c897aa0d81cf86927fee78", - "sha256:ec61d826d80fc293ed46c9dd26995921e3a82146feacd952ef0757236fc137be", - "sha256:ee04010f26d5102399bd17f8df8bc38dc7ccd7701dc77f4a68c5b8d733406958", - "sha256:f3bc6af6e2b8f92eced34ef6a96ffb248e863af20ef4fde9448cc8c9b858b749", - "sha256:f7d6b36dd2e029b6bcb8a13cf19664c7b8e19ab3a58e0fefbb5b8461447ed5ec" + "sha256:0545de8c688fbbf3088f9e8b801157923be4bf8e7b03e97c2ecd4dfa39e48e0e", + "sha256:076b1ed2ac819933895b1a000904f62d615fe4533a5cf3e052ff9a1da560575c", + "sha256:0afad2cd484908f472c8fe2e8ef499facee54a0a6978be0e0cff67b1254fd747", + "sha256:0ccaa1bc98751fbfcf53dc8dfdb90d96e98838010fc254180dd6707a6e8bb179", + "sha256:0d3105efab7c5c091609abacad33afff33bdff0035bece164c98bcf5a85ef90a", + "sha256:0e1af74a9529a1137c67c887ed9cde62cff53aa4d84a3adbec329f9ec47a3936", + "sha256:136f9db0f53c0206db38b8cd0c985c78ded5fd596c9a86ce5c0b92afb91c3a19", + "sha256:156ececdf636143f508770bf8a3a0498de64da5abd890c7dbb42ca9e3b6c05b8", + "sha256:15c87339490100c63472a76d87fe7097a0835c705eb5ae79fd96e343473629ed", + "sha256:1695497bb2a02a6de60064c9f077a4ae9c25c73624e0d43e3aa9d16d983073c2", + "sha256:173563f3696124372831007e3d4b9821746964a95968628f7075d9231ac6bb33", + "sha256:173866d9f7409c0fb514cf6e78952e65816600cb888c68b37b41147349fe0057", + "sha256:23ec1d3c31882b2a8a69c801ef58ebf7bae2553211ebbddf04235be275a38548", + "sha256:243fbbbf003754fe41b5bdf10ce1e7f80bcc70732b5b54222c124d6b4c2ab31c", + "sha256:28c6cf1d92edf936ceedc7afa61b07e9d78a27b15244aa46bbcd534c7458ee1b", + "sha256:2aa738e0282be54eede1e3f36b81f1e46aee7ec7602aa563e81e0e8d7b67963f", + "sha256:2cf441c4b6e538ba0d2591574f95d3fdd33f1efafa864faa077d9636ecc0c4e9", + "sha256:30c3ff305f6e06650a761c4393666f77384f1cc6c5c0251965d6bfa5fbc88f7f", + "sha256:31561a5b4d8dbef1559b3600b045607cf804bae040f64b5f5bca77da38084a8a", + "sha256:32b66be100ac5739065496c74c4b7f3015cef792c3174982809274d7e51b3e04", + "sha256:3433da95b51a75692dcf6cc8117a31410447c75a9a8187888f02ad45c0a86c50", + "sha256:34a2d76a1984cac04ff8b1bfc939ec9dc0914821264d4a9c8fd0ed6aa8d4cfd2", + "sha256:353665775be69bbfc6d54c8d134bfc533e332149faeddd631b0bc79df0897f46", + "sha256:38d0124fa992dbacd0c48b1b755d3ee0a9f924f427f95b0ef376556a24debf01", + "sha256:3c56ec1eacd0a5d35b8a29f468659c47f4fe61b2cab948ca756c39b7617f0aa5", + "sha256:3db817b4e95eb05c362e3b45dafe7144b18603e1211f4a5b36eb9522ecc62bcf", + "sha256:3e52474256a7db9dcf3c5f4ca0b300fdea6c21cca0148c8891d03a025649d935", + "sha256:416f2e3beaeae81e2f7a45dc711258be5bdc79c940a9a270b266c0bec038fb84", + "sha256:435aca062444a7f0c884861d2e3ea79883bd1cd19d0a381928b69ae1b85bc51d", + "sha256:4388c72174868884f76affcdd3656544c426407e0043c89b684d22fb265e04a5", + "sha256:43ebdcc120e2ca679dba01a779333a8ea76b50547b55e812b8b92818d604662c", + "sha256:458c0c65802d816a6b955cf3603186de79e8fdb46d4f19abaec4ef0a906f50a7", + "sha256:533a28754e7f7439f217550a497bb026c54072dbe16402b183fdbca2431935a9", + "sha256:553dad9af802a9ad1a6525e7528152a015b85fb8dbf764ebfc755c695f488367", + "sha256:5838f2b79dc8f96fdc44077c9e4e2e33d7089b10788464609df788eb97d03aad", + "sha256:5b48388ded01f6f2429a8c55012bdbd1c2a0c3735b3e73e221649e524c34a58d", + "sha256:5bc0df728e4def5e15a754521e8882ba5a5121bd6b5a3a0ff7efda5d6558ab3d", + "sha256:63eab904f8630aed5a68f2d0aeab565dcfc595dc1bf0b91b71d9ddd43dea3aea", + "sha256:66f629632220a4e7858b58e4857927dd01a850a4cef2fb4044c8662787165cf7", + "sha256:670eb11325ed3a6209339974b276811867defe52f4188fe18dc49855774fa9cf", + "sha256:69d5856d526802cbda768d3e6246cd0d77450fa2a4bc2ea0ea14f0d972c2894b", + "sha256:6e840553c9c494a35e449a987ca2c4f8372668ee954a03a9a9685075228e5036", + "sha256:711bdfae4e699a6d4f371137cbe9e740dc958530cb920eb6f43ff9551e17cfbc", + "sha256:74abb8709ea54cc483c4fb57fb17bb66f8e0f04438cff6ded322074dbd17c7ec", + "sha256:75119badf45f7183e10e348edff5a76a94dc19ba9287d94001ff05e81475967b", + "sha256:766dcc00b943c089349d4060b935c76281f6be225e39994c2ccec3a2a36ad627", + "sha256:78e6fdc976ec966b99e4daa3812fac0274cc28cd2b24b0d92462e2e5ef90d368", + "sha256:81dadafb3aa124f86dc267a2168f71bbd2bfb163663661ab0038f6e4b8edb810", + "sha256:82d5161e8cb8f36ec778fd7ac4d740415d84030f5b9ef8fe4da54784a1f46c94", + "sha256:833547179c31f9bec39b49601d282d6f0ea1633620701288934c5f66d88c3e50", + "sha256:856b7f1a7b98a8c31823285786bd566cf06226ac4f38b3ef462f593c608a9bd6", + "sha256:8657d3f37f781d987037f9cc20bbc8b40425fa14380c87da0cb8dfce7c92d0fb", + "sha256:93bed8a8084544c6efe8856c362af08a23e959340c87a95687fdbe9c9f280c8b", + "sha256:954dde77c404084c2544e572f342aef384240b3e434e06cecc71597e95fd1ce7", + "sha256:98f68df80ec6ca3015186b2677c208c096d646ef37bbf8b49764ab4a38183931", + "sha256:99e12d2bf587b44deb74e0d6170fec37adb489964dbca656ec41a7cd8f2ff178", + "sha256:9a13a07532e8e1c4a5a3afff0ca4553da23409fad65def1b71186fb867eeae8d", + "sha256:9c1e3ff4b89cdd2e1a24c214f141e848b9e0451f08d7d4963cb4108d4d798f1f", + "sha256:9ce2e0f6123a60bd1a7f5ae3b2c49b240c12c132847f17aa990b841a417598a2", + "sha256:9fcda20b2de7042cc35cf911702fa3d8311bd40055a14446c1e62403684afdc5", + "sha256:a32d58f4b521bb98b2c0aa9da407f8bd57ca81f34362bcb090e4a79e9924fefc", + "sha256:a39c36f4218a5bb668b4f06874d676d35a035ee668e6e7e3538835c703634b84", + "sha256:a5cafb02cf097a82d74403f7e0b6b9df3ffbfe8edf9415ea816314711764a27b", + "sha256:a7cf963a357c5f00cb55b1955df8bbe68d2f2f65de065160a1c26b85a1e44172", + "sha256:a880372e2e5dbb9258a4e8ff43f13888039abb9dd6d515f28611c54361bc5644", + "sha256:ace4cad790f3bf872c082366c9edd7f8f8f77afe3992b134cfc810332206884f", + "sha256:af8ff8d7dc07ce873f643de6dfbcd45dc3db2c87462e5c387267197f59e6d776", + "sha256:b47a6000a7e833ebfe5886b56a31cb2ff12120b1efd4578a6fcc38df16cc77bd", + "sha256:b71862a652f50babab4a43a487f157d26b464b1dedbcc0afda02fd64f3809d04", + "sha256:b7f227ca6db5a9fda0a2b935a2ea34a7267589ffc63c8045f0e4edb8d8dcf956", + "sha256:bc8936d06cd53fddd4892677d65e98af514c8d78c79864f418bbf78a4a2edde4", + "sha256:bed1b5dbf90bad3bfc19439258c97873eab453c71d8b6869c136346acfe497e7", + "sha256:c45817e3e6972109d1a2c65091504a537e257bc3c885b4e78a95baa96df6a3f8", + "sha256:c68e820879ff39992c7f148113b46efcd6ec765a4865581f2902b3c43a5f4bbb", + "sha256:c77494a2f2282d9bbbbcab7c227a4d1b4bb829875c96251f66fb5f3bae4fb053", + "sha256:c998d0558805860503bc3a595994895ca0f7835e00668dadc673bbf7f5fbfcbe", + "sha256:ccad2800dfdff34392448c4bf834be124f10a5bc102f254521d931c1c53c455a", + "sha256:cd126498171f752dd85737ab1544329a4520c53eed3997f9b08aefbafb1cc53b", + "sha256:ce44217ad99ffad8027d2fde0269ae368c86db66ea0571c62a000798d69401fb", + "sha256:d1ac2bc069f4a458634c26b101c2341b18da85cb96afe0015990507efec2e417", + "sha256:d417a4f6943112fae3924bae2af7112562285848d9bcee737fc4ff7cbd450e6c", + "sha256:d538df442c0d9665664ab6dd5fccd0110fa3b364914f9c85b3ef9b7b2e157980", + "sha256:ded1b1803151dd0f20a8945508786d57c2f97a50289b16f2629f85433e546d47", + "sha256:e2e93b88ecc8f74074012e18d679fb2e9c746f2a56f79cd5e2b1afcf2a8a786b", + "sha256:e4ca3b9f370f218cc2a0309542cab8d0acdfd66667e7c37d04d617012485f904", + "sha256:e4ee8b8639070ff246ad3649294336b06db37a94bdea0d09ea491603e0be73b8", + "sha256:e52f77a0cd246086afde8815039f3e16f8d2be51786c0a39b57104c563c5cbb0", + "sha256:eaea112aed589131f73d50d570a6864728bd7c0c66ef6c9154ed7b59f24da611", + "sha256:ed20a4bdc635f36cb19e630bfc644181dd075839b6fc84cac51c0f381ac472e2", + "sha256:eedc3f247ee7b3808ea07205f3e7d7879bc19ad3e6222195cd5fbf9988853e4d", + "sha256:f0e1844ad47c7bd5d6fa784f1d4accc5f4168b48999303a868fe0f8597bde715", + "sha256:f4fe99ce44128c71233d0d72152db31ca119711dfc5f2c82385ad611d8d7f897", + "sha256:f8cfd847e6b9ecf9f2f2531c8427035f291ec286c0a4944b0a9fce58c6446046", + "sha256:f9ca0e6ce7774dc7830dc0cc4bb6b3eec769db667f230e7c770a628c1aa5681b", + "sha256:fa2bea05ff0a8fb4d8124498e00e02398f06d23cdadd0fe027d84a3f7afde31e", + "sha256:fbbb63bed5fcd70cd3dd23a087cd78e4675fb5a2963b8af53f945cbbca79ae16", + "sha256:fbda058a9a68bec347962595f50546a8a4a34fd7b0654a7b9697917dc2bf810d", + "sha256:ffd591e22b22f9cb48e472529db6a47203c41c2c5911ff0a52e85723196c0d75" ], - "markers": "python_version >= '3.7'", - "version": "==1.9.4" + "markers": "python_version >= '3.8'", + "version": "==1.15.2" }, "zope.event": { "hashes": [ @@ -2866,43 +1754,46 @@ }, "zope.interface": { "hashes": [ - "sha256:03bd5c0db82237bbc47833a8b25f1cc090646e212f86b601903d79d7e6b37031", - "sha256:03f1452d5d1f279184d5bdb663a3dc39902d9320eceb63276240791e849054b6", - "sha256:10ebac566dd0cec66f942dc759d46a994a2b3ba7179420f0e2130f88f8a5f400", - "sha256:192b7a792e3145ed880ff6b1a206fdb783697cfdb4915083bfca7065ec845e60", - "sha256:19c829d52e921b9fe0b2c0c6a8f9a2508c49678ee1be598f87d143335b6a35dc", - "sha256:3f3495462bc0438b76536a0e10d765b168ae636092082531b88340dc40dcd118", - "sha256:3f52050c6a10d4a039ec6f2c58e5b3ade5cc570d16cf9d102711e6b8413c90e6", - "sha256:400d06c9ec8dbcc96f56e79376297e7be07a315605c9a2208720da263d44d76f", - "sha256:4ec212037becf6d2f705b7ed4538d56980b1e7bba237df0d8995cbbed29961dc", - "sha256:51d5713e8e38f2d3ec26e0dfdca398ed0c20abda2eb49ffc15a15a23eb8e5f6d", - "sha256:52f5253cca1b35eaeefa51abd366b87f48f8714097c99b131ba61f3fdbbb58e7", - "sha256:5566fd9271c89ad03d81b0831c37d46ae5e2ed211122c998637130159a120cf1", - "sha256:55bbcc74dc0c7ab489c315c28b61d7a1d03cf938cc99cc58092eb065f120c3a5", - "sha256:696c2a381fc7876b3056711717dba5eddd07c2c9e5ccd50da54029a1293b6e43", - "sha256:6ba4b3638d014918b918aa90a9c8370bd74a03abf8fcf9deb353b3a461a59a84", - "sha256:7039e624bcb820f77cc2ff3d1adcce531932990eee16121077eb51d9c76b6c14", - "sha256:88d108d004e0df25224de77ce349a7e73494ea2cb194031f7c9687e68a88ec9b", - "sha256:8c1dff87b30fd150c61367d0e2cdc49bb55f8b9fd2a303560bbc24b951573ae1", - "sha256:9a8195b99e650e6f329ce4e5eb22d448bdfef0406404080812bc96e2a05674cb", - "sha256:af0b33f04677b57843d529b9257a475d2865403300b48c67654c40abac2f9f24", - "sha256:b419f2144e1762ab845f20316f1df36b15431f2622ebae8a6d5f7e8e712b413c", - "sha256:b59deb0ddc7b431e41d720c00f99d68b52cb9bd1d5605a085dc18f502fe9c47f", - "sha256:bc0615351221926a36a0fbcb2520fb52e0b23e8c22a43754d9cb8f21358c33c0", - "sha256:c203d82069ba31e1f3bc7ba530b2461ec86366cd4bfc9b95ec6ce58b1b559c34", - "sha256:ce6cbb852fb8f2f9bb7b9cdca44e2e37bce783b5f4c167ff82cb5f5128163c8f", - "sha256:d33cb526efdc235a2531433fc1287fcb80d807d5b401f9b801b78bf22df560dd", - "sha256:da0cef4d7e3f19c3bd1d71658d6900321af0492fee36ec01b550a10924cffb9c", - "sha256:da21e7eec49252df34d426c2ee9cf0361c923026d37c24728b0fa4cc0599fd03", - "sha256:ea8d51e5eb29e57d34744369cd08267637aa5a0fefc9b5d33775ab7ff2ebf2e3", - "sha256:ec4e87e6fdc511a535254daa122c20e11959ce043b4e3425494b237692a34f1c", - "sha256:f0f5fda7cbf890371a59ab1d06512da4f2c89a6ea194e595808123c863c38eff", - "sha256:f32ca483e6ade23c7caaee9d5ee5d550cf4146e9b68d2fb6c68bac183aa41c37", - "sha256:f749ca804648d00eda62fe1098f229b082dfca930d8bad8386e572a6eafa7525", - "sha256:f89a420cf5a6f2aa7849dd59e1ff0e477f562d97cf8d6a1ee03461e1eec39887" + "sha256:07add15de0cc7e69917f7d286b64d54125c950aeb43efed7a5ea7172f000fbc1", + "sha256:0ac20581fc6cd7c754f6dff0ae06fedb060fa0e9ea6309d8be8b2701d9ea51c4", + "sha256:124149e2d42067b9c6597f4dafdc7a0983d0163868f897b7bb5dc850b14f9a87", + "sha256:27cfb5205d68b12682b6e55ab8424662d96e8ead19550aad0796b08dd2c9a45e", + "sha256:2a29ac607e970b5576547f0e3589ec156e04de17af42839eedcf478450687317", + "sha256:2b6a4924f5bad9fe21d99f66a07da60d75696a136162427951ec3cb223a5570d", + "sha256:2bd9e9f366a5df08ebbdc159f8224904c1c5ce63893984abb76954e6fbe4381a", + "sha256:3bcff5c09d0215f42ba64b49205a278e44413d9bf9fa688fd9e42bfe472b5f4f", + "sha256:3f005869a1a05e368965adb2075f97f8ee9a26c61898a9e52a9764d93774f237", + "sha256:4a00ead2e24c76436e1b457a5132d87f83858330f6c923640b7ef82d668525d1", + "sha256:4af4a12b459a273b0b34679a5c3dc5e34c1847c3dd14a628aa0668e19e638ea2", + "sha256:5501e772aff595e3c54266bc1bfc5858e8f38974ce413a8f1044aae0f32a83a3", + "sha256:5e28ea0bc4b084fc93a483877653a033062435317082cdc6388dec3438309faf", + "sha256:5e956b1fd7f3448dd5e00f273072e73e50dfafcb35e4227e6d5af208075593c9", + "sha256:5fcf379b875c610b5a41bc8a891841533f98de0520287d7f85e25386cd10d3e9", + "sha256:6159e767d224d8f18deff634a1d3722e68d27488c357f62ebeb5f3e2f5288b1f", + "sha256:661d5df403cd3c5b8699ac480fa7f58047a3253b029db690efa0c3cf209993ef", + "sha256:711eebc77f2092c6a8b304bad0b81a6ce3cf5490b25574e7309fbc07d881e3af", + "sha256:80a3c00b35f6170be5454b45abe2719ea65919a2f09e8a6e7b1362312a872cd3", + "sha256:848b6fa92d7c8143646e64124ed46818a0049a24ecc517958c520081fd147685", + "sha256:91b6c30689cfd87c8f264acb2fc16ad6b3c72caba2aec1bf189314cf1a84ca33", + "sha256:9733a9a0f94ef53d7aa64661811b20875b5bc6039034c6e42fb9732170130573", + "sha256:9940d5bc441f887c5f375ec62bcf7e7e495a2d5b1da97de1184a88fb567f06af", + "sha256:9e3e48f3dea21c147e1b10c132016cb79af1159facca9736d231694ef5a740a8", + "sha256:a14c9decf0eb61e0892631271d500c1e306c7b6901c998c7035e194d9150fdd1", + "sha256:a735f82d2e3ed47ca01a20dfc4c779b966b16352650a8036ab3955aad151ed8a", + "sha256:a99240b1d02dc469f6afbe7da1bf617645e60290c272968f4e53feec18d7dce8", + "sha256:b7b25db127db3e6b597c5f74af60309c4ad65acd826f89609662f0dc33a54728", + "sha256:b936d61dbe29572fd2cfe13e30b925e5383bed1aba867692670f5a2a2eb7b4e9", + "sha256:bec001798ab62c3fc5447162bf48496ae9fba02edc295a9e10a0b0c639a6452e", + "sha256:cc8a318162123eddbdf22fcc7b751288ce52e4ad096d3766ff1799244352449d", + "sha256:d0a45b5af9f72c805ee668d1479480ca85169312211bed6ed18c343e39307d5f", + "sha256:e53c291debef523b09e1fe3dffe5f35dde164f1c603d77f770b88a1da34b7ed6", + "sha256:ec1ef1fdb6f014d5886b97e52b16d0f852364f447d2ab0f0c6027765777b6667", + "sha256:ec59fe53db7d32abb96c6d4efeed84aab4a7c38c62d7a901a9b20c09dd936e7a", + "sha256:f245d039f72e6f802902375755846f5de1ee1e14c3e8736c078565599bcab621", + "sha256:ff115ef91c0eeac69cd92daeba36a9d8e14daee445b504eeea2b1c0b55821984" ], "markers": "python_version >= '3.8'", - "version": "==7.0.1" + "version": "==7.1.0" } }, "develop": { @@ -2943,259 +1834,264 @@ }, "certifi": { "hashes": [ - "sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b", - "sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90" + "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8", + "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9" ], "markers": "python_version >= '3.6'", - "version": "==2024.7.4" + "version": "==2024.8.30" }, "cffi": { "hashes": [ - "sha256:011aff3524d578a9412c8b3cfaa50f2c0bd78e03eb7af7aa5e0df59b158efb2f", - "sha256:0a048d4f6630113e54bb4b77e315e1ba32a5a31512c31a273807d0027a7e69ab", - "sha256:0bb15e7acf8ab35ca8b24b90af52c8b391690ef5c4aec3d31f38f0d37d2cc499", - "sha256:0d46ee4764b88b91f16661a8befc6bfb24806d885e27436fdc292ed7e6f6d058", - "sha256:0e60821d312f99d3e1569202518dddf10ae547e799d75aef3bca3a2d9e8ee693", - "sha256:0fdacad9e0d9fc23e519efd5ea24a70348305e8d7d85ecbb1a5fa66dc834e7fb", - "sha256:14b9cbc8f7ac98a739558eb86fabc283d4d564dafed50216e7f7ee62d0d25377", - "sha256:17c6d6d3260c7f2d94f657e6872591fe8733872a86ed1345bda872cfc8c74885", - "sha256:1a2ddbac59dc3716bc79f27906c010406155031a1c801410f1bafff17ea304d2", - "sha256:2404f3de742f47cb62d023f0ba7c5a916c9c653d5b368cc966382ae4e57da401", - "sha256:24658baf6224d8f280e827f0a50c46ad819ec8ba380a42448e24459daf809cf4", - "sha256:24aa705a5f5bd3a8bcfa4d123f03413de5d86e497435693b638cbffb7d5d8a1b", - "sha256:2770bb0d5e3cc0e31e7318db06efcbcdb7b31bcb1a70086d3177692a02256f59", - "sha256:331ad15c39c9fe9186ceaf87203a9ecf5ae0ba2538c9e898e3a6967e8ad3db6f", - "sha256:3aa9d43b02a0c681f0bfbc12d476d47b2b2b6a3f9287f11ee42989a268a1833c", - "sha256:41f4915e09218744d8bae14759f983e466ab69b178de38066f7579892ff2a555", - "sha256:4304d4416ff032ed50ad6bb87416d802e67139e31c0bde4628f36a47a3164bfa", - "sha256:435a22d00ec7d7ea533db494da8581b05977f9c37338c80bc86314bec2619424", - "sha256:45f7cd36186db767d803b1473b3c659d57a23b5fa491ad83c6d40f2af58e4dbb", - "sha256:48b389b1fd5144603d61d752afd7167dfd205973a43151ae5045b35793232aa2", - "sha256:4e67d26532bfd8b7f7c05d5a766d6f437b362c1bf203a3a5ce3593a645e870b8", - "sha256:516a405f174fd3b88829eabfe4bb296ac602d6a0f68e0d64d5ac9456194a5b7e", - "sha256:5ba5c243f4004c750836f81606a9fcb7841f8874ad8f3bf204ff5e56332b72b9", - "sha256:5bdc0f1f610d067c70aa3737ed06e2726fd9d6f7bfee4a351f4c40b6831f4e82", - "sha256:6107e445faf057c118d5050560695e46d272e5301feffda3c41849641222a828", - "sha256:6327b572f5770293fc062a7ec04160e89741e8552bf1c358d1a23eba68166759", - "sha256:669b29a9eca6146465cc574659058ed949748f0809a2582d1f1a324eb91054dc", - "sha256:6ce01337d23884b21c03869d2f68c5523d43174d4fc405490eb0091057943118", - "sha256:6d872186c1617d143969defeadac5a904e6e374183e07977eedef9c07c8953bf", - "sha256:6f76a90c345796c01d85e6332e81cab6d70de83b829cf1d9762d0a3da59c7932", - "sha256:70d2aa9fb00cf52034feac4b913181a6e10356019b18ef89bc7c12a283bf5f5a", - "sha256:7cbc78dc018596315d4e7841c8c3a7ae31cc4d638c9b627f87d52e8abaaf2d29", - "sha256:856bf0924d24e7f93b8aee12a3a1095c34085600aa805693fb7f5d1962393206", - "sha256:8a98748ed1a1df4ee1d6f927e151ed6c1a09d5ec21684de879c7ea6aa96f58f2", - "sha256:93a7350f6706b31f457c1457d3a3259ff9071a66f312ae64dc024f049055f72c", - "sha256:964823b2fc77b55355999ade496c54dde161c621cb1f6eac61dc30ed1b63cd4c", - "sha256:a003ac9edc22d99ae1286b0875c460351f4e101f8c9d9d2576e78d7e048f64e0", - "sha256:a0ce71725cacc9ebf839630772b07eeec220cbb5f03be1399e0457a1464f8e1a", - "sha256:a47eef975d2b8b721775a0fa286f50eab535b9d56c70a6e62842134cf7841195", - "sha256:a8b5b9712783415695663bd463990e2f00c6750562e6ad1d28e072a611c5f2a6", - "sha256:a9015f5b8af1bb6837a3fcb0cdf3b874fe3385ff6274e8b7925d81ccaec3c5c9", - "sha256:aec510255ce690d240f7cb23d7114f6b351c733a74c279a84def763660a2c3bc", - "sha256:b00e7bcd71caa0282cbe3c90966f738e2db91e64092a877c3ff7f19a1628fdcb", - "sha256:b50aaac7d05c2c26dfd50c3321199f019ba76bb650e346a6ef3616306eed67b0", - "sha256:b7b6ea9e36d32582cda3465f54c4b454f62f23cb083ebc7a94e2ca6ef011c3a7", - "sha256:bb9333f58fc3a2296fb1d54576138d4cf5d496a2cc118422bd77835e6ae0b9cb", - "sha256:c1c13185b90bbd3f8b5963cd8ce7ad4ff441924c31e23c975cb150e27c2bf67a", - "sha256:c3b8bd3133cd50f6b637bb4322822c94c5ce4bf0d724ed5ae70afce62187c492", - "sha256:c5d97162c196ce54af6700949ddf9409e9833ef1003b4741c2b39ef46f1d9720", - "sha256:c815270206f983309915a6844fe994b2fa47e5d05c4c4cef267c3b30e34dbe42", - "sha256:cab2eba3830bf4f6d91e2d6718e0e1c14a2f5ad1af68a89d24ace0c6b17cced7", - "sha256:d1df34588123fcc88c872f5acb6f74ae59e9d182a2707097f9e28275ec26a12d", - "sha256:d6bdcd415ba87846fd317bee0774e412e8792832e7805938987e4ede1d13046d", - "sha256:db9a30ec064129d605d0f1aedc93e00894b9334ec74ba9c6bdd08147434b33eb", - "sha256:dbc183e7bef690c9abe5ea67b7b60fdbca81aa8da43468287dae7b5c046107d4", - "sha256:dca802c8db0720ce1c49cce1149ff7b06e91ba15fa84b1d59144fef1a1bc7ac2", - "sha256:dec6b307ce928e8e112a6bb9921a1cb00a0e14979bf28b98e084a4b8a742bd9b", - "sha256:df8bb0010fdd0a743b7542589223a2816bdde4d94bb5ad67884348fa2c1c67e8", - "sha256:e4094c7b464cf0a858e75cd14b03509e84789abf7b79f8537e6a72152109c76e", - "sha256:e4760a68cab57bfaa628938e9c2971137e05ce48e762a9cb53b76c9b569f1204", - "sha256:eb09b82377233b902d4c3fbeeb7ad731cdab579c6c6fda1f763cd779139e47c3", - "sha256:eb862356ee9391dc5a0b3cbc00f416b48c1b9a52d252d898e5b7696a5f9fe150", - "sha256:ef9528915df81b8f4c7612b19b8628214c65c9b7f74db2e34a646a0a2a0da2d4", - "sha256:f3157624b7558b914cb039fd1af735e5e8049a87c817cc215109ad1c8779df76", - "sha256:f3e0992f23bbb0be00a921eae5363329253c3b86287db27092461c887b791e5e", - "sha256:f9338cc05451f1942d0d8203ec2c346c830f8e86469903d5126c1f0a13a2bcbb", - "sha256:ffef8fd58a36fb5f1196919638f73dd3ae0db1a878982b27a9a5a176ede4ba91" + "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8", + "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2", + "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1", + "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15", + "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36", + "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", + "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8", + "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36", + "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17", + "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf", + "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc", + "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3", + "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed", + "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702", + "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1", + "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8", + "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903", + "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6", + "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d", + "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b", + "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e", + "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be", + "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c", + "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683", + "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9", + "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c", + "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8", + "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1", + "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4", + "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655", + "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67", + "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595", + "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0", + "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65", + "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41", + "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6", + "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401", + "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6", + "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3", + "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16", + "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93", + "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e", + "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4", + "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964", + "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c", + "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576", + "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0", + "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3", + "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662", + "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3", + "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff", + "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5", + "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd", + "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f", + "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5", + "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14", + "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d", + "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9", + "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7", + "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382", + "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a", + "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e", + "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a", + "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4", + "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99", + "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87", + "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b" ], "markers": "platform_python_implementation != 'PyPy'", - "version": "==1.17.0" + "version": "==1.17.1" }, "charset-normalizer": { "hashes": [ - "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027", - "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087", - "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786", - "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8", - "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09", - "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185", - "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574", - "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e", - "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519", - "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898", - "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269", - "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3", - "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f", - "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6", - "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8", - "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a", - "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73", - "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc", - "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714", - "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2", - "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc", - "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce", - "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d", - "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e", - "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6", - "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269", - "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96", - "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d", - "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a", - "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4", - "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77", - "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d", - "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0", - "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed", - "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068", - "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac", - "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25", - "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8", - "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab", - "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26", - "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2", - "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db", - "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f", - "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5", - "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99", - "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c", - "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d", - "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811", - "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa", - "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a", - "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03", - "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b", - "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04", - "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c", - "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001", - "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458", - "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389", - "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99", - "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985", - "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537", - "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238", - "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f", - "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d", - "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796", - "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a", - "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143", - "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8", - "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c", - "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5", - "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5", - "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711", - "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4", - "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6", - "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c", - "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7", - "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4", - "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b", - "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae", - "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12", - "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c", - "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae", - "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8", - "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887", - "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b", - "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4", - "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f", - "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5", - "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33", - "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519", - "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561" + "sha256:0099d79bdfcf5c1f0c2c72f91516702ebf8b0b8ddd8905f97a8aecf49712c621", + "sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6", + "sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8", + "sha256:0b309d1747110feb25d7ed6b01afdec269c647d382c857ef4663bbe6ad95a912", + "sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c", + "sha256:0de7b687289d3c1b3e8660d0741874abe7888100efe14bd0f9fd7141bcbda92b", + "sha256:1110e22af8ca26b90bd6364fe4c763329b0ebf1ee213ba32b68c73de5752323d", + "sha256:130272c698667a982a5d0e626851ceff662565379baf0ff2cc58067b81d4f11d", + "sha256:136815f06a3ae311fae551c3df1f998a1ebd01ddd424aa5603a4336997629e95", + "sha256:14215b71a762336254351b00ec720a8e85cada43b987da5a042e4ce3e82bd68e", + "sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565", + "sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64", + "sha256:2006769bd1640bdf4d5641c69a3d63b71b81445473cac5ded39740a226fa88ab", + "sha256:20587d20f557fe189b7947d8e7ec5afa110ccf72a3128d61a2a387c3313f46be", + "sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e", + "sha256:27623ba66c183eca01bf9ff833875b459cad267aeeb044477fedac35e19ba907", + "sha256:285e96d9d53422efc0d7a17c60e59f37fbf3dfa942073f666db4ac71e8d726d0", + "sha256:2de62e8801ddfff069cd5c504ce3bc9672b23266597d4e4f50eda28846c322f2", + "sha256:2f6c34da58ea9c1a9515621f4d9ac379871a8f21168ba1b5e09d74250de5ad62", + "sha256:309a7de0a0ff3040acaebb35ec45d18db4b28232f21998851cfa709eeff49d62", + "sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23", + "sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc", + "sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284", + "sha256:40d3ff7fc90b98c637bda91c89d51264a3dcf210cade3a2c6f838c7268d7a4ca", + "sha256:425c5f215d0eecee9a56cdb703203dda90423247421bf0d67125add85d0c4455", + "sha256:43193c5cda5d612f247172016c4bb71251c784d7a4d9314677186a838ad34858", + "sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b", + "sha256:47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594", + "sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc", + "sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db", + "sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b", + "sha256:4ec9dd88a5b71abfc74e9df5ebe7921c35cbb3b641181a531ca65cdb5e8e4dea", + "sha256:4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6", + "sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920", + "sha256:55f56e2ebd4e3bc50442fbc0888c9d8c94e4e06a933804e2af3e89e2f9c1c749", + "sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7", + "sha256:5d447056e2ca60382d460a604b6302d8db69476fd2015c81e7c35417cfabe4cd", + "sha256:5ed2e36c3e9b4f21dd9422f6893dec0abf2cca553af509b10cd630f878d3eb99", + "sha256:5ff2ed8194587faf56555927b3aa10e6fb69d931e33953943bc4f837dfee2242", + "sha256:62f60aebecfc7f4b82e3f639a7d1433a20ec32824db2199a11ad4f5e146ef5ee", + "sha256:63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129", + "sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2", + "sha256:6b493a043635eb376e50eedf7818f2f322eabbaa974e948bd8bdd29eb7ef2a51", + "sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee", + "sha256:6fd30dc99682dc2c603c2b315bded2799019cea829f8bf57dc6b61efde6611c8", + "sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b", + "sha256:7706f5850360ac01d80c89bcef1640683cc12ed87f42579dab6c5d3ed6888613", + "sha256:7782afc9b6b42200f7362858f9e73b1f8316afb276d316336c0ec3bd73312742", + "sha256:79983512b108e4a164b9c8d34de3992f76d48cadc9554c9e60b43f308988aabe", + "sha256:7f683ddc7eedd742e2889d2bfb96d69573fde1d92fcb811979cdb7165bb9c7d3", + "sha256:82357d85de703176b5587dbe6ade8ff67f9f69a41c0733cf2425378b49954de5", + "sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631", + "sha256:86f4e8cca779080f66ff4f191a685ced73d2f72d50216f7112185dc02b90b9b7", + "sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15", + "sha256:8ce7fd6767a1cc5a92a639b391891bf1c268b03ec7e021c7d6d902285259685c", + "sha256:8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea", + "sha256:9289fd5dddcf57bab41d044f1756550f9e7cf0c8e373b8cdf0ce8773dc4bd417", + "sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250", + "sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88", + "sha256:95c3c157765b031331dd4db3c775e58deaee050a3042fcad72cbc4189d7c8dca", + "sha256:980b4f289d1d90ca5efcf07958d3eb38ed9c0b7676bf2831a54d4f66f9c27dfa", + "sha256:9ae4ef0b3f6b41bad6366fb0ea4fc1d7ed051528e113a60fa2a65a9abb5b1d99", + "sha256:9c98230f5042f4945f957d006edccc2af1e03ed5e37ce7c373f00a5a4daa6149", + "sha256:9fa2566ca27d67c86569e8c85297aaf413ffab85a8960500f12ea34ff98e4c41", + "sha256:a14969b8691f7998e74663b77b4c36c0337cb1df552da83d5c9004a93afdb574", + "sha256:a8aacce6e2e1edcb6ac625fb0f8c3a9570ccc7bfba1f63419b3769ccf6a00ed0", + "sha256:a8e538f46104c815be19c975572d74afb53f29650ea2025bbfaef359d2de2f7f", + "sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d", + "sha256:aa693779a8b50cd97570e5a0f343538a8dbd3e496fa5dcb87e29406ad0299654", + "sha256:ab22fbd9765e6954bc0bcff24c25ff71dcbfdb185fcdaca49e81bac68fe724d3", + "sha256:ab2e5bef076f5a235c3774b4f4028a680432cded7cad37bba0fd90d64b187d19", + "sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90", + "sha256:af73657b7a68211996527dbfeffbb0864e043d270580c5aef06dc4b659a4b578", + "sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9", + "sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1", + "sha256:b8831399554b92b72af5932cdbbd4ddc55c55f631bb13ff8fe4e6536a06c5c51", + "sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719", + "sha256:bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236", + "sha256:bd7af3717683bea4c87acd8c0d3d5b44d56120b26fd3f8a692bdd2d5260c620a", + "sha256:bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c", + "sha256:c3e446d253bd88f6377260d07c895816ebf33ffffd56c1c792b13bff9c3e1ade", + "sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944", + "sha256:c94057af19bc953643a33581844649a7fdab902624d2eb739738a30e2b3e60fc", + "sha256:cab5d0b79d987c67f3b9e9c53f54a61360422a5a0bc075f43cab5621d530c3b6", + "sha256:ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6", + "sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27", + "sha256:d5b054862739d276e09928de37c79ddeec42a6e1bfc55863be96a36ba22926f6", + "sha256:dbe03226baf438ac4fda9e2d0715022fd579cb641c4cf639fa40d53b2fe6f3e2", + "sha256:dc15e99b2d8a656f8e666854404f1ba54765871104e50c8e9813af8a7db07f12", + "sha256:dcaf7c1524c0542ee2fc82cc8ec337f7a9f7edee2532421ab200d2b920fc97cf", + "sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114", + "sha256:dd9a8bd8900e65504a305bf8ae6fa9fbc66de94178c420791d0293702fce2df7", + "sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf", + "sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d", + "sha256:e91f541a85298cf35433bf66f3fab2a4a2cff05c127eeca4af174f6d497f0d4b", + "sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed", + "sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03", + "sha256:f09cb5a7bbe1ecae6e87901a2eb23e0256bb524a79ccc53eb0b7629fbe7677c4", + "sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67", + "sha256:f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365", + "sha256:f28f891ccd15c514a0981f3b9db9aa23d62fe1a99997512b0491d2ed323d229a", + "sha256:f3e73a4255342d4eb26ef6df01e3962e73aa29baa3124a8e824c5d3364a65748", + "sha256:f606a1881d2663630ea5b8ce2efe2111740df4b687bd78b34a8131baa007f79b", + "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079", + "sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482" ], "markers": "python_full_version >= '3.7.0'", - "version": "==3.3.2" + "version": "==3.4.0" }, "coverage": { "hashes": [ - "sha256:06a737c882bd26d0d6ee7269b20b12f14a8704807a01056c80bb881a4b2ce6ca", - "sha256:07e2ca0ad381b91350c0ed49d52699b625aab2b44b65e1b4e02fa9df0e92ad2d", - "sha256:0c0420b573964c760df9e9e86d1a9a622d0d27f417e1a949a8a66dd7bcee7bc6", - "sha256:0dbde0f4aa9a16fa4d754356a8f2e36296ff4d83994b2c9d8398aa32f222f989", - "sha256:1125ca0e5fd475cbbba3bb67ae20bd2c23a98fac4e32412883f9bcbaa81c314c", - "sha256:13b0a73a0896988f053e4fbb7de6d93388e6dd292b0d87ee51d106f2c11b465b", - "sha256:166811d20dfea725e2e4baa71fffd6c968a958577848d2131f39b60043400223", - "sha256:170d444ab405852903b7d04ea9ae9b98f98ab6d7e63e1115e82620807519797f", - "sha256:1f4aa8219db826ce6be7099d559f8ec311549bfc4046f7f9fe9b5cea5c581c56", - "sha256:225667980479a17db1048cb2bf8bfb39b8e5be8f164b8f6628b64f78a72cf9d3", - "sha256:260933720fdcd75340e7dbe9060655aff3af1f0c5d20f46b57f262ab6c86a5e8", - "sha256:2bdb062ea438f22d99cba0d7829c2ef0af1d768d1e4a4f528087224c90b132cb", - "sha256:2c09f4ce52cb99dd7505cd0fc8e0e37c77b87f46bc9c1eb03fe3bc9991085388", - "sha256:3115a95daa9bdba70aea750db7b96b37259a81a709223c8448fa97727d546fe0", - "sha256:3e0cadcf6733c09154b461f1ca72d5416635e5e4ec4e536192180d34ec160f8a", - "sha256:3f1156e3e8f2872197af3840d8ad307a9dd18e615dc64d9ee41696f287c57ad8", - "sha256:4421712dbfc5562150f7554f13dde997a2e932a6b5f352edcce948a815efee6f", - "sha256:44df346d5215a8c0e360307d46ffaabe0f5d3502c8a1cefd700b34baf31d411a", - "sha256:502753043567491d3ff6d08629270127e0c31d4184c4c8d98f92c26f65019962", - "sha256:547f45fa1a93154bd82050a7f3cddbc1a7a4dd2a9bf5cb7d06f4ae29fe94eaf8", - "sha256:5621a9175cf9d0b0c84c2ef2b12e9f5f5071357c4d2ea6ca1cf01814f45d2391", - "sha256:609b06f178fe8e9f89ef676532760ec0b4deea15e9969bf754b37f7c40326dbc", - "sha256:645786266c8f18a931b65bfcefdbf6952dd0dea98feee39bd188607a9d307ed2", - "sha256:6878ef48d4227aace338d88c48738a4258213cd7b74fd9a3d4d7582bb1d8a155", - "sha256:6a89ecca80709d4076b95f89f308544ec8f7b4727e8a547913a35f16717856cb", - "sha256:6db04803b6c7291985a761004e9060b2bca08da6d04f26a7f2294b8623a0c1a0", - "sha256:6e2cd258d7d927d09493c8df1ce9174ad01b381d4729a9d8d4e38670ca24774c", - "sha256:6e81d7a3e58882450ec4186ca59a3f20a5d4440f25b1cff6f0902ad890e6748a", - "sha256:702855feff378050ae4f741045e19a32d57d19f3e0676d589df0575008ea5004", - "sha256:78b260de9790fd81e69401c2dc8b17da47c8038176a79092a89cb2b7d945d060", - "sha256:7bb65125fcbef8d989fa1dd0e8a060999497629ca5b0efbca209588a73356232", - "sha256:7dea0889685db8550f839fa202744652e87c60015029ce3f60e006f8c4462c93", - "sha256:8284cf8c0dd272a247bc154eb6c95548722dce90d098c17a883ed36e67cdb129", - "sha256:877abb17e6339d96bf08e7a622d05095e72b71f8afd8a9fefc82cf30ed944163", - "sha256:8929543a7192c13d177b770008bc4e8119f2e1f881d563fc6b6305d2d0ebe9de", - "sha256:8ae539519c4c040c5ffd0632784e21b2f03fc1340752af711f33e5be83a9d6c6", - "sha256:8f59d57baca39b32db42b83b2a7ba6f47ad9c394ec2076b084c3f029b7afca23", - "sha256:9054a0754de38d9dbd01a46621636689124d666bad1936d76c0341f7d71bf569", - "sha256:953510dfb7b12ab69d20135a0662397f077c59b1e6379a768e97c59d852ee51d", - "sha256:95cae0efeb032af8458fc27d191f85d1717b1d4e49f7cb226cf526ff28179778", - "sha256:9bc572be474cafb617672c43fe989d6e48d3c83af02ce8de73fff1c6bb3c198d", - "sha256:9c56863d44bd1c4fe2abb8a4d6f5371d197f1ac0ebdee542f07f35895fc07f36", - "sha256:9e0b2df163b8ed01d515807af24f63de04bebcecbd6c3bfeff88385789fdf75a", - "sha256:a09ece4a69cf399510c8ab25e0950d9cf2b42f7b3cb0374f95d2e2ff594478a6", - "sha256:a1ac0ae2b8bd743b88ed0502544847c3053d7171a3cff9228af618a068ed9c34", - "sha256:a318d68e92e80af8b00fa99609796fdbcdfef3629c77c6283566c6f02c6d6704", - "sha256:a4acd025ecc06185ba2b801f2de85546e0b8ac787cf9d3b06e7e2a69f925b106", - "sha256:a6d3adcf24b624a7b778533480e32434a39ad8fa30c315208f6d3e5542aeb6e9", - "sha256:a78d169acd38300060b28d600344a803628c3fd585c912cacc9ea8790fe96862", - "sha256:a95324a9de9650a729239daea117df21f4b9868ce32e63f8b650ebe6cef5595b", - "sha256:abd5fd0db5f4dc9289408aaf34908072f805ff7792632250dcb36dc591d24255", - "sha256:b06079abebbc0e89e6163b8e8f0e16270124c154dc6e4a47b413dd538859af16", - "sha256:b43c03669dc4618ec25270b06ecd3ee4fa94c7f9b3c14bae6571ca00ef98b0d3", - "sha256:b48f312cca9621272ae49008c7f613337c53fadca647d6384cc129d2996d1133", - "sha256:b5d7b556859dd85f3a541db6a4e0167b86e7273e1cdc973e5b175166bb634fdb", - "sha256:b9f222de8cded79c49bf184bdbc06630d4c58eec9459b939b4a690c82ed05657", - "sha256:c3c02d12f837d9683e5ab2f3d9844dc57655b92c74e286c262e0fc54213c216d", - "sha256:c44fee9975f04b33331cb8eb272827111efc8930cfd582e0320613263ca849ca", - "sha256:cf4b19715bccd7ee27b6b120e7e9dd56037b9c0681dcc1adc9ba9db3d417fa36", - "sha256:d0c212c49b6c10e6951362f7c6df3329f04c2b1c28499563d4035d964ab8e08c", - "sha256:d3296782ca4eab572a1a4eca686d8bfb00226300dcefdf43faa25b5242ab8a3e", - "sha256:d85f5e9a5f8b73e2350097c3756ef7e785f55bd71205defa0bfdaf96c31616ff", - "sha256:da511e6ad4f7323ee5702e6633085fb76c2f893aaf8ce4c51a0ba4fc07580ea7", - "sha256:e05882b70b87a18d937ca6768ff33cc3f72847cbc4de4491c8e73880766718e5", - "sha256:e61c0abb4c85b095a784ef23fdd4aede7a2628478e7baba7c5e3deba61070a02", - "sha256:e6a08c0be454c3b3beb105c0596ebdc2371fab6bb90c0c0297f4e58fd7e1012c", - "sha256:e9a6e0eb86070e8ccaedfbd9d38fec54864f3125ab95419970575b42af7541df", - "sha256:ed37bd3c3b063412f7620464a9ac1314d33100329f39799255fb8d3027da50d3", - "sha256:f1adfc8ac319e1a348af294106bc6a8458a0f1633cc62a1446aebc30c5fa186a", - "sha256:f5796e664fe802da4f57a168c85359a8fbf3eab5e55cd4e4569fbacecc903959", - "sha256:fc5a77d0c516700ebad189b587de289a20a78324bc54baee03dd486f0855d234", - "sha256:fd21f6ae3f08b41004dfb433fa895d858f3f5979e7762d052b12aef444e29afc" + "sha256:04f2189716e85ec9192df307f7c255f90e78b6e9863a03223c3b998d24a3c6c6", + "sha256:0c6c0f4d53ef603397fc894a895b960ecd7d44c727df42a8d500031716d4e8d2", + "sha256:0ca37993206402c6c35dc717f90d4c8f53568a8b80f0bf1a1b2b334f4d488fba", + "sha256:12f9515d875859faedb4144fd38694a761cd2a61ef9603bf887b13956d0bbfbb", + "sha256:1990b1f4e2c402beb317840030bb9f1b6a363f86e14e21b4212e618acdfce7f6", + "sha256:2341a78ae3a5ed454d524206a3fcb3cec408c2a0c7c2752cd78b606a2ff15af4", + "sha256:23bb63ae3f4c645d2d82fa22697364b0046fbafb6261b258a58587441c5f7bd0", + "sha256:27bd5f18d8f2879e45724b0ce74f61811639a846ff0e5c0395b7818fae87aec6", + "sha256:2dc7d6b380ca76f5e817ac9eef0c3686e7834c8346bef30b041a4ad286449990", + "sha256:331b200ad03dbaa44151d74daeb7da2cf382db424ab923574f6ecca7d3b30de3", + "sha256:365defc257c687ce3e7d275f39738dcd230777424117a6c76043459db131dd43", + "sha256:37be7b5ea3ff5b7c4a9db16074dc94523b5f10dd1f3b362a827af66a55198175", + "sha256:3c2e6fa98032fec8282f6b27e3f3986c6e05702828380618776ad794e938f53a", + "sha256:40e8b1983080439d4802d80b951f4a93d991ef3261f69e81095a66f86cf3c3c6", + "sha256:43517e1f6b19f610a93d8227e47790722c8bf7422e46b365e0469fc3d3563d97", + "sha256:43b32a06c47539fe275106b376658638b418c7cfdfff0e0259fbf877e845f14b", + "sha256:43d6a66e33b1455b98fc7312b124296dad97a2e191c80320587234a77b1b736e", + "sha256:4c59d6a4a4633fad297f943c03d0d2569867bd5372eb5684befdff8df8522e39", + "sha256:52ac29cc72ee7e25ace7807249638f94c9b6a862c56b1df015d2b2e388e51dbd", + "sha256:54356a76b67cf8a3085818026bb556545ebb8353951923b88292556dfa9f812d", + "sha256:583049c63106c0555e3ae3931edab5669668bbef84c15861421b94e121878d3f", + "sha256:6d99198203f0b9cb0b5d1c0393859555bc26b548223a769baf7e321a627ed4fc", + "sha256:6da42bbcec130b188169107ecb6ee7bd7b4c849d24c9370a0c884cf728d8e976", + "sha256:6e484e479860e00da1f005cd19d1c5d4a813324e5951319ac3f3eefb497cc549", + "sha256:70a6756ce66cd6fe8486c775b30889f0dc4cb20c157aa8c35b45fd7868255c5c", + "sha256:70d24936ca6c15a3bbc91ee9c7fc661132c6f4c9d42a23b31b6686c05073bde5", + "sha256:71967c35828c9ff94e8c7d405469a1fb68257f686bca7c1ed85ed34e7c2529c4", + "sha256:79644f68a6ff23b251cae1c82b01a0b51bc40c8468ca9585c6c4b1aeee570e0b", + "sha256:87cd2e29067ea397a47e352efb13f976eb1b03e18c999270bb50589323294c6e", + "sha256:8d4c6ea0f498c7c79111033a290d060c517853a7bcb2f46516f591dab628ddd3", + "sha256:9134032f5aa445ae591c2ba6991d10136a1f533b1d2fa8f8c21126468c5025c6", + "sha256:921fbe13492caf6a69528f09d5d7c7d518c8d0e7b9f6701b7719715f29a71e6e", + "sha256:99670790f21a96665a35849990b1df447993880bb6463a0a1d757897f30da929", + "sha256:9975442f2e7a5cfcf87299c26b5a45266ab0696348420049b9b94b2ad3d40234", + "sha256:99ded130555c021d99729fabd4ddb91a6f4cc0707df4b1daf912c7850c373b13", + "sha256:a3328c3e64ea4ab12b85999eb0779e6139295bbf5485f69d42cf794309e3d007", + "sha256:a4fb91d5f72b7e06a14ff4ae5be625a81cd7e5f869d7a54578fc271d08d58ae3", + "sha256:aa23ce39661a3e90eea5f99ec59b763b7d655c2cada10729ed920a38bfc2b167", + "sha256:aac7501ae73d4a02f4b7ac8fcb9dc55342ca98ffb9ed9f2dfb8a25d53eda0e4d", + "sha256:ab84a8b698ad5a6c365b08061920138e7a7dd9a04b6feb09ba1bfae68346ce6d", + "sha256:b4adeb878a374126f1e5cf03b87f66279f479e01af0e9a654cf6d1509af46c40", + "sha256:b9853509b4bf57ba7b1f99b9d866c422c9c5248799ab20e652bbb8a184a38181", + "sha256:bb7d5fe92bd0dc235f63ebe9f8c6e0884f7360f88f3411bfed1350c872ef2054", + "sha256:bca4c8abc50d38f9773c1ec80d43f3768df2e8576807d1656016b9d3eeaa96fd", + "sha256:c222958f59b0ae091f4535851cbb24eb57fc0baea07ba675af718fb5302dddb2", + "sha256:c30e42ea11badb147f0d2e387115b15e2bd8205a5ad70d6ad79cf37f6ac08c91", + "sha256:c3a79f56dee9136084cf84a6c7c4341427ef36e05ae6415bf7d787c96ff5eaa3", + "sha256:c51ef82302386d686feea1c44dbeef744585da16fcf97deea2a8d6c1556f519b", + "sha256:c77326300b839c44c3e5a8fe26c15b7e87b2f32dfd2fc9fee1d13604347c9b38", + "sha256:d33a785ea8354c480515e781554d3be582a86297e41ccbea627a5c632647f2cd", + "sha256:d546cfa78844b8b9c1c0533de1851569a13f87449897bbc95d698d1d3cb2a30f", + "sha256:da29ceabe3025a1e5a5aeeb331c5b1af686daab4ff0fb4f83df18b1180ea83e2", + "sha256:df8c05a0f574d480947cba11b947dc41b1265d721c3777881da2fb8d3a1ddfba", + "sha256:e266af4da2c1a4cbc6135a570c64577fd3e6eb204607eaff99d8e9b710003c6f", + "sha256:e279f3db904e3b55f520f11f983cc8dc8a4ce9b65f11692d4718ed021ec58b83", + "sha256:ea52bd218d4ba260399a8ae4bb6b577d82adfc4518b93566ce1fddd4a49d1dce", + "sha256:ebec65f5068e7df2d49466aab9128510c4867e532e07cb6960075b27658dca38", + "sha256:ec1e3b40b82236d100d259854840555469fad4db64f669ab817279eb95cd535c", + "sha256:ee77c7bef0724165e795b6b7bf9c4c22a9b8468a6bdb9c6b4281293c6b22a90f", + "sha256:f263b18692f8ed52c8de7f40a0751e79015983dbd77b16906e5b310a39d3ca21", + "sha256:f7b26757b22faf88fcf232f5f0e62f6e0fd9e22a8a5d0d5016888cdfe1f6c1c4", + "sha256:f7ddb920106bbbbcaf2a274d56f46956bf56ecbde210d88061824a95bdd94e92" ], "index": "pypi", - "markers": "python_version >= '3.8'", - "version": "==7.6.1" + "markers": "python_version >= '3.9'", + "version": "==7.6.3" }, "docker": { "hashes": [ @@ -3213,11 +2109,11 @@ }, "idna": { "hashes": [ - "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc", - "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0" + "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", + "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3" ], - "markers": "python_version >= '3.5'", - "version": "==3.7" + "markers": "python_version >= '3.6'", + "version": "==3.10" }, "iniconfig": { "hashes": [ @@ -3229,21 +2125,21 @@ }, "minio": { "hashes": [ - "sha256:aa3b485788b63b12406a5798465d12a57e4be2ac2a58a8380959b6b748e64ddd", - "sha256:f8af2dafc22ebe1aef3ac181b8e217037011c430aa6da276ed627e55aaf7c815" + "sha256:a83c2fcd981944602a8dc11e8e07543ed9cda0a9462264e3f46a13171c56bccb", + "sha256:fe5523d9c4a4d6cfc07e96905852841bccdb22b22770e1efca4bf5ae8b65774b" ], "index": "pypi", "markers": "python_version >= '3.9'", - "version": "==7.2.8" + "version": "==7.2.9" }, "opensearch-py": { "hashes": [ - "sha256:6a36535efcda870c820fd84c4bda96d7d57fc900a8c7dec660a48c079904df97", - "sha256:c09a73727868c29f86ffbed1e987afb7f86bcce983b28bf69249cfad8c831d68" + "sha256:5417650eba98a1c7648e502207cebf3a12beab623ffe0ebbf55f9b1b4b6e44e9", + "sha256:67ab76e9373669bc71da417096df59827c08369ac3795d5438c9a8be21cbd759" ], "index": "pypi", "markers": "python_version >= '3.8' and python_version < '4'", - "version": "==2.7.0" + "version": "==2.7.1" }, "packaging": { "hashes": [ @@ -3271,50 +2167,50 @@ }, "pycryptodome": { "hashes": [ - "sha256:06d6de87c19f967f03b4cf9b34e538ef46e99a337e9a61a77dbe44b2cbcf0690", - "sha256:09609209ed7de61c2b560cc5c8c4fbf892f8b15b1faf7e4cbffac97db1fffda7", - "sha256:210ba1b647837bfc42dd5a813cdecb5b86193ae11a3f5d972b9a0ae2c7e9e4b4", - "sha256:2a1250b7ea809f752b68e3e6f3fd946b5939a52eaeea18c73bdab53e9ba3c2dd", - "sha256:2ab6ab0cb755154ad14e507d1df72de9897e99fd2d4922851a276ccc14f4f1a5", - "sha256:3427d9e5310af6680678f4cce149f54e0bb4af60101c7f2c16fdf878b39ccccc", - "sha256:3cd3ef3aee1079ae44afaeee13393cf68b1058f70576b11439483e34f93cf818", - "sha256:405002eafad114a2f9a930f5db65feef7b53c4784495dd8758069b89baf68eab", - "sha256:417a276aaa9cb3be91f9014e9d18d10e840a7a9b9a9be64a42f553c5b50b4d1d", - "sha256:4401564ebf37dfde45d096974c7a159b52eeabd9969135f0426907db367a652a", - "sha256:49a4c4dc60b78ec41d2afa392491d788c2e06edf48580fbfb0dd0f828af49d25", - "sha256:5601c934c498cd267640b57569e73793cb9a83506f7c73a8ec57a516f5b0b091", - "sha256:6e0e4a987d38cfc2e71b4a1b591bae4891eeabe5fa0f56154f576e26287bfdea", - "sha256:76658f0d942051d12a9bd08ca1b6b34fd762a8ee4240984f7c06ddfb55eaf15a", - "sha256:76cb39afede7055127e35a444c1c041d2e8d2f1f9c121ecef573757ba4cd2c3c", - "sha256:8d6b98d0d83d21fb757a182d52940d028564efe8147baa9ce0f38d057104ae72", - "sha256:9b3ae153c89a480a0ec402e23db8d8d84a3833b65fa4b15b81b83be9d637aab9", - "sha256:a60fedd2b37b4cb11ccb5d0399efe26db9e0dd149016c1cc6c8161974ceac2d6", - "sha256:ac1c7c0624a862f2e53438a15c9259d1655325fc2ec4392e66dc46cdae24d044", - "sha256:acae12b9ede49f38eb0ef76fdec2df2e94aad85ae46ec85be3648a57f0a7db04", - "sha256:acc2614e2e5346a4a4eab6e199203034924313626f9620b7b4b38e9ad74b7e0c", - "sha256:acf6e43fa75aca2d33e93409f2dafe386fe051818ee79ee8a3e21de9caa2ac9e", - "sha256:baee115a9ba6c5d2709a1e88ffe62b73ecc044852a925dcb67713a288c4ec70f", - "sha256:c18b381553638414b38705f07d1ef0a7cf301bc78a5f9bc17a957eb19446834b", - "sha256:d29daa681517f4bc318cd8a23af87e1f2a7bad2fe361e8aa29c77d652a065de4", - "sha256:d5954acfe9e00bc83ed9f5cb082ed22c592fbbef86dc48b907238be64ead5c33", - "sha256:ec0bb1188c1d13426039af8ffcb4dbe3aad1d7680c35a62d8eaf2a529b5d3d4f", - "sha256:ec1f93feb3bb93380ab0ebf8b859e8e5678c0f010d2d78367cf6bc30bfeb148e", - "sha256:f0e6d631bae3f231d3634f91ae4da7a960f7ff87f2865b2d2b831af1dfb04e9a", - "sha256:f35d6cee81fa145333137009d9c8ba90951d7d77b67c79cbe5f03c7eb74d8fe2", - "sha256:f47888542a0633baff535a04726948e876bf1ed880fddb7c10a736fa99146ab3", - "sha256:fb3b87461fa35afa19c971b0a2b7456a7b1db7b4eba9a8424666104925b78128" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==3.20.0" + "sha256:0714206d467fc911042d01ea3a1847c847bc10884cf674c82e12915cfe1649f8", + "sha256:0fa0a05a6a697ccbf2a12cec3d6d2650b50881899b845fac6e87416f8cb7e87d", + "sha256:0fd54003ec3ce4e0f16c484a10bc5d8b9bd77fa662a12b85779a2d2d85d67ee0", + "sha256:18caa8cfbc676eaaf28613637a89980ad2fd96e00c564135bf90bc3f0b34dd93", + "sha256:2480ec2c72438430da9f601ebc12c518c093c13111a5c1644c82cdfc2e50b1e4", + "sha256:26412b21df30b2861424a6c6d5b1d8ca8107612a4cfa4d0183e71c5d200fb34a", + "sha256:280b67d20e33bb63171d55b1067f61fbd932e0b1ad976b3a184303a3dad22764", + "sha256:2cb635b67011bc147c257e61ce864879ffe6d03342dc74b6045059dfbdedafca", + "sha256:2de4b7263a33947ff440412339cb72b28a5a4c769b5c1ca19e33dd6cd1dcec6e", + "sha256:3ba4cc304eac4d4d458f508d4955a88ba25026890e8abff9b60404f76a62c55e", + "sha256:4c26a2f0dc15f81ea3afa3b0c87b87e501f235d332b7f27e2225ecb80c0b1cdd", + "sha256:590ef0898a4b0a15485b05210b4a1c9de8806d3ad3d47f74ab1dc07c67a6827f", + "sha256:5dfafca172933506773482b0e18f0cd766fd3920bd03ec85a283df90d8a17bc6", + "sha256:6cce52e196a5f1d6797ff7946cdff2038d3b5f0aba4a43cb6bf46b575fd1b5bb", + "sha256:7cb087b8612c8a1a14cf37dd754685be9a8d9869bed2ffaaceb04850a8aeef7e", + "sha256:7d85c1b613121ed3dbaa5a97369b3b757909531a959d229406a75b912dd51dd1", + "sha256:7ee86cbde706be13f2dec5a42b52b1c1d1cbb90c8e405c68d0755134735c8dc6", + "sha256:8898a66425a57bcf15e25fc19c12490b87bd939800f39a03ea2de2aea5e3611a", + "sha256:8acd7d34af70ee63f9a849f957558e49a98f8f1634f86a59d2be62bb8e93f71c", + "sha256:932c905b71a56474bff8a9c014030bc3c882cee696b448af920399f730a650c2", + "sha256:a1752eca64c60852f38bb29e2c86fca30d7672c024128ef5d70cc15868fa10f4", + "sha256:a3804675283f4764a02db05f5191eb8fec2bb6ca34d466167fc78a5f05bbe6b3", + "sha256:a4e74c522d630766b03a836c15bff77cb657c5fdf098abf8b1ada2aebc7d0819", + "sha256:a915597ffccabe902e7090e199a7bf7a381c5506a747d5e9d27ba55197a2c568", + "sha256:b7aa25fc0baa5b1d95b7633af4f5f1838467f1815442b22487426f94e0d66c53", + "sha256:cc2269ab4bce40b027b49663d61d816903a4bd90ad88cb99ed561aadb3888dd3", + "sha256:d5ebe0763c982f069d3877832254f64974139f4f9655058452603ff559c482e8", + "sha256:dad9bf36eda068e89059d1f07408e397856be9511d7113ea4b586642a429a4fd", + "sha256:de18954104667f565e2fbb4783b56667f30fb49c4d79b346f52a29cb198d5b6b", + "sha256:f35e442630bc4bc2e1878482d6f59ea22e280d7121d7adeaedba58c23ab6386b", + "sha256:f7787e0d469bdae763b876174cf2e6c0f7be79808af26b1da96f1a64bcf47297", + "sha256:ff99f952db3db2fbe98a0b355175f93ec334ba3d01bbde25ad3a5a33abc02b58" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", + "version": "==3.21.0" }, "pytest": { "hashes": [ - "sha256:4ba08f9ae7dcf84ded419494d229b48d0903ea6407b030eaec46df5e6a73bba5", - "sha256:c132345d12ce551242c87269de812483f5bcc87cdbb4722e48487ba194f9fdce" + "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181", + "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==8.3.2" + "version": "==8.3.3" }, "python-dateutil": { "hashes": [ @@ -3378,16 +2274,16 @@ "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8" ], - "markers": "python_version < '3.13'", + "markers": "python_version >= '3.8'", "version": "==4.12.2" }, "urllib3": { "hashes": [ - "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472", - "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168" + "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac", + "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9" ], - "markers": "python_version >= '3.10'", - "version": "==2.2.2" + "markers": "python_version >= '3.8'", + "version": "==2.2.3" }, "wrapt": { "hashes": [ diff --git a/dbrepo-analyse-service/app.py b/dbrepo-analyse-service/app.py index 9fc99d76d895136ccc1d705fb25739d6637eb42b..8431e41052e3dfb900954af644739e5815738daa 100644 --- a/dbrepo-analyse-service/app.py +++ b/dbrepo-analyse-service/app.py @@ -204,7 +204,7 @@ template = { "info": { "title": "Database Repository Analyse Service API", "description": "Service that analyses data structures", - "version": "1.4.5", + "version": "1.4.7", "contact": { "name": "Prof. Andreas Rauber", "email": "andreas.rauber@tuwien.ac.at" @@ -216,7 +216,7 @@ template = { }, "externalDocs": { "description": "Sourcecode Documentation", - "url": "https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.4.5/" + "url": "https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.4.7/" }, "servers": [ { diff --git a/dbrepo-analyse-service/lib/dbrepo-1.4.6.tar.gz b/dbrepo-analyse-service/lib/dbrepo-1.4.6.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..958287917e7f2b38a0286c3e91c2d471462bceee Binary files /dev/null and b/dbrepo-analyse-service/lib/dbrepo-1.4.6.tar.gz differ diff --git a/dbrepo-analyse-service/lib/dbrepo-1.4.6rc1-py3-none-any.whl b/dbrepo-analyse-service/lib/dbrepo-1.4.6rc1-py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..83944ce88d8aec5a3b767aa09caf9a8700323104 Binary files /dev/null and b/dbrepo-analyse-service/lib/dbrepo-1.4.6rc1-py3-none-any.whl differ diff --git a/dbrepo-analyse-service/lib/dbrepo-1.4.6rc1.tar.gz b/dbrepo-analyse-service/lib/dbrepo-1.4.6rc1.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..a0c8432134f3c21359cd7fb8ee1a341812a6c034 Binary files /dev/null and b/dbrepo-analyse-service/lib/dbrepo-1.4.6rc1.tar.gz differ diff --git a/dbrepo-analyse-service/lib/dbrepo-1.4.7.tar.gz b/dbrepo-analyse-service/lib/dbrepo-1.4.7.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..c652dbae4a60aae708eb6fe4e751977b97b72344 Binary files /dev/null and b/dbrepo-analyse-service/lib/dbrepo-1.4.7.tar.gz differ diff --git a/dbrepo-analyse-service/lib/dbrepo-1.4.7rc0-py3-none-any.whl b/dbrepo-analyse-service/lib/dbrepo-1.4.7rc0-py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..84353af6a26fdb3e281e10ab90d21130a0701258 Binary files /dev/null and b/dbrepo-analyse-service/lib/dbrepo-1.4.7rc0-py3-none-any.whl differ diff --git a/dbrepo-analyse-service/lib/dbrepo-1.4.7rc0.tar.gz b/dbrepo-analyse-service/lib/dbrepo-1.4.7rc0.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..735c2e9d3699303d119033e184e0cfb9a571317f Binary files /dev/null and b/dbrepo-analyse-service/lib/dbrepo-1.4.7rc0.tar.gz differ diff --git a/dbrepo-auth-service/Dockerfile b/dbrepo-auth-service/Dockerfile deleted file mode 100644 index 47fabff4ed802e5ccf1f066250b174a04f041847..0000000000000000000000000000000000000000 --- a/dbrepo-auth-service/Dockerfile +++ /dev/null @@ -1,56 +0,0 @@ -###### FIRST STAGE ###### -FROM keycloak/keycloak:24.0 AS config -LABEL org.opencontainers.image.authors="martin.weise@tuwien.ac.at" - -# Enable health and metrics support -ENV KC_HEALTH_ENABLED=true -ENV KC_METRICS_ENABLED=true -ENV KC_HTTP_RELATIVE_PATH=/api/auth - -# Configure a database vendor -ENV KC_DB=mariadb - -WORKDIR /opt/keycloak - -COPY ./server.keystore ./conf/server.keystore - -RUN /opt/keycloak/bin/kc.sh build - -###### SECOND STAGE ###### -FROM redhat/ubi9-minimal AS binary - -RUN microdnf update -y && microdnf install -y curl-minimal libcurl-minimal - -###### THIRD STAGE ###### -FROM keycloak/keycloak:21.0 AS runtime - -COPY --from=config /opt/keycloak/ /opt/keycloak/ -COPY --from=binary /usr/lib64 /usr/lib64 -COPY --from=binary /usr/bin/curl /usr/bin/curl - -USER root - -COPY ./dbrepo-realm.json /opt/keycloak/data/import/dbrepo-realm.json - -WORKDIR /app - -COPY ./docker-entrypoint.sh ./docker-entrypoint.sh -COPY ./disable-tls.sh ./disable-tls.sh - -ENV AUTH_DB=keycloak -ENV AUTH_USERNAME=root -ENV AUTH_PASSWORD=dbrepo - -ENV KC_DB=mariadb -ENV KC_DB_URL=jdbc:mariadb://auth-db/${AUTH_DB} -ENV KC_DB_USERNAME=${AUTH_USERNAME} -ENV KC_DB_PASSWORD=${AUTH_PASSWORD} -ENV KC_HOSTNAME_STRICT_HTTPS=false -ENV KC_HOSTNAME_PATH=/api/auth -ENV KC_HOSTNAME_ADMIN_URL=http://localhost/api/auth - -ENV KEYCLOAK_IMPORT=/opt/keycloak/data/import/dbrepo-realm.json -ENV KEYCLOAK_ADMIN=fda -ENV KEYCLOAK_ADMIN_PASSWORD=fda - -ENTRYPOINT [ "bash", "/app/docker-entrypoint.sh" ] diff --git a/dbrepo-auth-service/dbrepo-realm.json b/dbrepo-auth-service/dbrepo-realm.json index a39f7de1b0ab0611057af4890ee281bb202609ca..e057f778d4796aa1fd90c94c920a4abcec720de2 100644 --- a/dbrepo-auth-service/dbrepo-realm.json +++ b/dbrepo-auth-service/dbrepo-realm.json @@ -530,7 +530,7 @@ "description" : "${default-container-handling}", "composite" : true, "composites" : { - "realm" : [ "find-container", "list-containers" ] + "realm" : [ "find-container" ] }, "clientRole" : false, "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", @@ -2143,7 +2143,7 @@ "subType" : "anonymous", "subComponents" : { }, "config" : { - "allowed-protocol-mapper-types" : [ "oidc-full-name-mapper", "saml-user-attribute-mapper", "saml-user-property-mapper", "saml-role-list-mapper", "oidc-usermodel-attribute-mapper", "oidc-usermodel-property-mapper", "oidc-address-mapper", "oidc-sha256-pairwise-sub-mapper" ] + "allowed-protocol-mapper-types" : [ "saml-user-attribute-mapper", "oidc-full-name-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-address-mapper", "saml-user-property-mapper", "oidc-usermodel-property-mapper", "oidc-usermodel-attribute-mapper", "saml-role-list-mapper" ] } }, { "id" : "1849e52a-b8c9-44a8-af3d-ee19376a1ed1", @@ -2169,7 +2169,7 @@ "subType" : "authenticated", "subComponents" : { }, "config" : { - "allowed-protocol-mapper-types" : [ "saml-user-property-mapper", "oidc-usermodel-property-mapper", "saml-role-list-mapper", "oidc-address-mapper", "saml-user-attribute-mapper", "oidc-full-name-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-usermodel-attribute-mapper" ] + "allowed-protocol-mapper-types" : [ "saml-role-list-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-full-name-mapper", "oidc-usermodel-property-mapper", "oidc-usermodel-attribute-mapper", "saml-user-property-mapper", "saml-user-attribute-mapper", "oidc-address-mapper" ] } } ], "org.keycloak.storage.UserStorageProvider" : [ { @@ -2185,8 +2185,8 @@ "config" : { "ldap.attribute" : [ "createTimestamp" ], "is.mandatory.in.ldap" : [ "false" ], - "always.read.value.from.ldap" : [ "true" ], "read.only" : [ "true" ], + "always.read.value.from.ldap" : [ "true" ], "user.model.attribute" : [ "createTimestamp" ] } }, { @@ -2209,8 +2209,8 @@ "config" : { "ldap.attribute" : [ "cn" ], "is.mandatory.in.ldap" : [ "true" ], - "read.only" : [ "false" ], "always.read.value.from.ldap" : [ "true" ], + "read.only" : [ "false" ], "user.model.attribute" : [ "firstName" ] } }, { @@ -2221,8 +2221,8 @@ "config" : { "ldap.attribute" : [ "mail" ], "is.mandatory.in.ldap" : [ "false" ], - "read.only" : [ "false" ], "always.read.value.from.ldap" : [ "false" ], + "read.only" : [ "false" ], "user.model.attribute" : [ "email" ] } }, { @@ -2238,10 +2238,10 @@ "groups.dn" : [ "ou=users,dc=dbrepo,dc=at" ], "mode" : [ "LDAP_ONLY" ], "user.roles.retrieve.strategy" : [ "LOAD_GROUPS_BY_MEMBER_ATTRIBUTE" ], - "membership.ldap.attribute" : [ "member" ], "ignore.missing.groups" : [ "false" ], - "group.object.classes" : [ "groupOfNames" ], + "membership.ldap.attribute" : [ "member" ], "memberof.ldap.attribute" : [ "memberOf" ], + "group.object.classes" : [ "groupOfNames" ], "groups.path" : [ "/" ], "drop.non.existing.groups.during.sync" : [ "false" ] } @@ -2253,8 +2253,8 @@ "config" : { "ldap.attribute" : [ "modifyTimestamp" ], "is.mandatory.in.ldap" : [ "false" ], - "always.read.value.from.ldap" : [ "true" ], "read.only" : [ "true" ], + "always.read.value.from.ldap" : [ "true" ], "user.model.attribute" : [ "modifyTimestamp" ] } }, { @@ -2267,15 +2267,15 @@ "is.mandatory.in.ldap" : [ "true" ], "attribute.force.default" : [ "false" ], "is.binary.attribute" : [ "false" ], - "always.read.value.from.ldap" : [ "false" ], "read.only" : [ "false" ], + "always.read.value.from.ldap" : [ "false" ], "user.model.attribute" : [ "username" ] } } ] }, "config" : { - "pagination" : [ "false" ], "fullSyncPeriod" : [ "-1" ], + "pagination" : [ "false" ], "startTls" : [ "false" ], "usersDn" : [ "ou=users,dc=dbrepo,dc=at" ], "connectionPooling" : [ "true" ], @@ -2283,9 +2283,9 @@ "useKerberosForPasswordAuthentication" : [ "false" ], "importEnabled" : [ "true" ], "enabled" : [ "true" ], - "usernameLDAPAttribute" : [ "uid" ], - "bindCredential" : [ "admin" ], "bindDn" : [ "cn=admin,dc=dbrepo,dc=at" ], + "bindCredential" : [ "admin" ], + "usernameLDAPAttribute" : [ "uid" ], "changedSyncPeriod" : [ "-1" ], "lastSync" : [ "1719252666" ], "vendor" : [ "other" ], diff --git a/dbrepo-auth-service/disable-tls.sh b/dbrepo-auth-service/disable-tls.sh deleted file mode 100644 index 10586260ba2442fe7a68537bdd121a99b0f0cda1..0000000000000000000000000000000000000000 --- a/dbrepo-auth-service/disable-tls.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash -while [ ! -f /opt/keycloak/tls_disabled ]; do - cd /opt/keycloak/bin || exit 1 - ./kcadm.sh config credentials --server http://localhost:8080 --realm master --user "${KEYCLOAK_ADMIN}" --password "${KEYCLOAK_ADMIN_PASSWORD}" - if [ "$?" -ne 0 ]; then - echo "Keycloak not yet ready ..." - echo "Wait 5s ..." - sleep 5 - else - ./kcadm.sh update realms/master -s sslRequired=NONE - touch /opt/keycloak/tls_disabled - fi -done \ No newline at end of file diff --git a/dbrepo-auth-service/docker-entrypoint.sh b/dbrepo-auth-service/docker-entrypoint.sh deleted file mode 100644 index b7eb09b2829423e01d3d61f7310fc98f31b28d01..0000000000000000000000000000000000000000 --- a/dbrepo-auth-service/docker-entrypoint.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash -bash /app/disable-tls.sh & -/opt/keycloak/bin/kc.sh start-dev --import-realm diff --git a/dbrepo-auth-service/export-realms.sh b/dbrepo-auth-service/export-realms.sh new file mode 100755 index 0000000000000000000000000000000000000000..ed9245b96980946de3aeb495c11e1f8a28b2270d --- /dev/null +++ b/dbrepo-auth-service/export-realms.sh @@ -0,0 +1,4 @@ +#!/bin/bash +docker exec -it dbrepo-auth-service kc.sh export --dir /opt/bitnami/keycloak/export +docker exec -it dbrepo-auth-service cat /opt/bitnami/keycloak/export/master-realm.json > ./dbrepo-auth-service/master-realm.json +docker exec -it dbrepo-auth-service cat /opt/bitnami/keycloak/export/dbrepo-realm.json > ./dbrepo-auth-service/dbrepo-realm.json \ No newline at end of file diff --git a/dbrepo-auth-service/generate-keystore.sh b/dbrepo-auth-service/generate-keystore.sh deleted file mode 100644 index 8b68c44a1febcac8c308a8c443a4a41f5ea21d2f..0000000000000000000000000000000000000000 --- a/dbrepo-auth-service/generate-keystore.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -keytool -genkey -alias server -keyalg RSA -keypass password -storepass password -keystore server.keystore \ No newline at end of file diff --git a/dbrepo-auth-service/import-realms.sh b/dbrepo-auth-service/import-realms.sh new file mode 100644 index 0000000000000000000000000000000000000000..662fbcf5a359bebb28f389bbb5ab3114c07ee015 --- /dev/null +++ b/dbrepo-auth-service/import-realms.sh @@ -0,0 +1,3 @@ +#!/bin/bash +kc.sh import --file /opt/keycloak/data/import/master-realm.json +kc.sh import --file /opt/keycloak/data/import/dbrepo-realm.json \ No newline at end of file diff --git a/dbrepo-auth-service/master-realm.json b/dbrepo-auth-service/master-realm.json new file mode 100644 index 0000000000000000000000000000000000000000..d6c46ccd15a4c1cfead9c6c76e72d10408100758 --- /dev/null +++ b/dbrepo-auth-service/master-realm.json @@ -0,0 +1,2853 @@ +{ + "id": "afe47bd0-61f8-40c3-95cb-04930407ebdd", + "realm": "master", + "displayName": "Keycloak", + "displayNameHtml": "", + "notBefore": 0, + "defaultSignatureAlgorithm": "RS256", + "revokeRefreshToken": false, + "refreshTokenMaxReuse": 0, + "accessTokenLifespan": 60, + "accessTokenLifespanForImplicitFlow": 900, + "ssoSessionIdleTimeout": 1800, + "ssoSessionMaxLifespan": 36000, + "ssoSessionIdleTimeoutRememberMe": 0, + "ssoSessionMaxLifespanRememberMe": 0, + "offlineSessionIdleTimeout": 2592000, + "offlineSessionMaxLifespanEnabled": false, + "offlineSessionMaxLifespan": 5184000, + "clientSessionIdleTimeout": 0, + "clientSessionMaxLifespan": 0, + "clientOfflineSessionIdleTimeout": 0, + "clientOfflineSessionMaxLifespan": 0, + "accessCodeLifespan": 60, + "accessCodeLifespanUserAction": 300, + "accessCodeLifespanLogin": 1800, + "actionTokenGeneratedByAdminLifespan": 43200, + "actionTokenGeneratedByUserLifespan": 300, + "oauth2DeviceCodeLifespan": 600, + "oauth2DevicePollingInterval": 5, + "enabled": true, + "sslRequired": "external", + "registrationAllowed": false, + "registrationEmailAsUsername": false, + "rememberMe": false, + "verifyEmail": false, + "loginWithEmailAllowed": true, + "duplicateEmailsAllowed": false, + "resetPasswordAllowed": false, + "editUsernameAllowed": false, + "bruteForceProtected": false, + "permanentLockout": false, + "maxTemporaryLockouts": 0, + "maxFailureWaitSeconds": 900, + "minimumQuickLoginWaitSeconds": 60, + "waitIncrementSeconds": 60, + "quickLoginCheckMilliSeconds": 1000, + "maxDeltaTimeSeconds": 43200, + "failureFactor": 30, + "roles": { + "realm": [ + { + "id": "01178d3c-65eb-406b-87a1-e7144f488028", + "name": "default-roles-master", + "description": "${role_default-roles}", + "composite": true, + "composites": { + "realm": [ + "offline_access", + "uma_authorization" + ], + "client": { + "account": [ + "view-profile", + "manage-account" + ] + } + }, + "clientRole": false, + "containerId": "afe47bd0-61f8-40c3-95cb-04930407ebdd", + "attributes": {} + }, + { + "id": "646cda2d-911d-459e-8522-b28ba3126341", + "name": "uma_authorization", + "description": "${role_uma_authorization}", + "composite": false, + "clientRole": false, + "containerId": "afe47bd0-61f8-40c3-95cb-04930407ebdd", + "attributes": {} + }, + { + "id": "344b3b83-99f7-43f7-8533-76f64195eab6", + "name": "offline_access", + "description": "${role_offline-access}", + "composite": false, + "clientRole": false, + "containerId": "afe47bd0-61f8-40c3-95cb-04930407ebdd", + "attributes": {} + }, + { + "id": "9ca176f3-c0c8-4ba1-8364-c38f3ce4f88b", + "name": "admin", + "description": "${role_admin}", + "composite": true, + "composites": { + "realm": [ + "create-realm" + ], + "client": { + "master-realm": [ + "manage-realm", + "view-events", + "view-authorization", + "manage-authorization", + "query-realms", + "query-clients", + "manage-clients", + "view-clients", + "create-client", + "impersonation", + "query-users", + "view-identity-providers", + "manage-users", + "manage-events", + "view-realm", + "query-groups", + "manage-identity-providers", + "view-users" + ], + "dbrepo-realm": [ + "manage-users", + "query-realms", + "query-groups", + "manage-identity-providers", + "manage-events", + "manage-authorization", + "query-users", + "manage-clients", + "view-users", + "view-events", + "view-authorization", + "query-clients", + "view-identity-providers", + "view-realm", + "view-clients", + "create-client", + "manage-realm", + "impersonation" + ] + } + }, + "clientRole": false, + "containerId": "afe47bd0-61f8-40c3-95cb-04930407ebdd", + "attributes": {} + }, + { + "id": "6e765f03-5dee-4061-b027-c3ec41114329", + "name": "default-system-roles", + "description": "${default-system-roles}", + "composite": true, + "composites": { + "realm": [ + "create-realm", + "default-roles-master", + "default-system-roles", + "offline_access", + "admin", + "uma_authorization" + ] + }, + "clientRole": false, + "containerId": "afe47bd0-61f8-40c3-95cb-04930407ebdd", + "attributes": {} + }, + { + "id": "3da4e842-c3cc-4bcd-a2f0-dec1ec36f3c5", + "name": "create-realm", + "description": "${role_create-realm}", + "composite": false, + "clientRole": false, + "containerId": "afe47bd0-61f8-40c3-95cb-04930407ebdd", + "attributes": {} + } + ], + "client": { + "security-admin-console": [], + "admin-cli": [], + "account-console": [], + "broker": [ + { + "id": "07de46e9-cc5c-4b50-8904-14443ed4d1f1", + "name": "read-token", + "description": "${role_read-token}", + "composite": false, + "clientRole": true, + "containerId": "217563ea-11c7-4c96-969b-af076d740f7c", + "attributes": {} + } + ], + "master-realm": [ + { + "id": "5c8f38f8-0a16-4f92-8fa2-81a6301f6215", + "name": "create-client", + "description": "${role_create-client}", + "composite": false, + "clientRole": true, + "containerId": "9a451e5c-a55a-4872-bee1-58af763101a1", + "attributes": {} + }, + { + "id": "d0ab2e61-c7e4-49f3-9af2-965f20ec725a", + "name": "manage-realm", + "description": "${role_manage-realm}", + "composite": false, + "clientRole": true, + "containerId": "9a451e5c-a55a-4872-bee1-58af763101a1", + "attributes": {} + }, + { + "id": "89d438ee-957d-435c-b201-5be06aee01fd", + "name": "view-events", + "description": "${role_view-events}", + "composite": false, + "clientRole": true, + "containerId": "9a451e5c-a55a-4872-bee1-58af763101a1", + "attributes": {} + }, + { + "id": "664a9190-f73f-4f83-83bc-a2185cea334c", + "name": "view-authorization", + "description": "${role_view-authorization}", + "composite": false, + "clientRole": true, + "containerId": "9a451e5c-a55a-4872-bee1-58af763101a1", + "attributes": {} + }, + { + "id": "b3c0e4db-5a09-4d1e-9ced-96a34efb6398", + "name": "manage-authorization", + "description": "${role_manage-authorization}", + "composite": false, + "clientRole": true, + "containerId": "9a451e5c-a55a-4872-bee1-58af763101a1", + "attributes": {} + }, + { + "id": "5cd61b20-da2b-4fed-b0c3-2fb5819ab06b", + "name": "query-realms", + "description": "${role_query-realms}", + "composite": false, + "clientRole": true, + "containerId": "9a451e5c-a55a-4872-bee1-58af763101a1", + "attributes": {} + }, + { + "id": "94ceae4b-2cb8-4d10-bf11-8ce5c1ec9c55", + "name": "impersonation", + "description": "${role_impersonation}", + "composite": false, + "clientRole": true, + "containerId": "9a451e5c-a55a-4872-bee1-58af763101a1", + "attributes": {} + }, + { + "id": "77072e30-3941-4b32-a8c8-76993fc507bb", + "name": "query-users", + "description": "${role_query-users}", + "composite": false, + "clientRole": true, + "containerId": "9a451e5c-a55a-4872-bee1-58af763101a1", + "attributes": {} + }, + { + "id": "ea00baa8-f64d-409d-936d-ecf0adec5a57", + "name": "view-identity-providers", + "description": "${role_view-identity-providers}", + "composite": false, + "clientRole": true, + "containerId": "9a451e5c-a55a-4872-bee1-58af763101a1", + "attributes": {} + }, + { + "id": "fb2c167e-fb6b-4db5-b0bf-d2c8454ceee5", + "name": "manage-users", + "description": "${role_manage-users}", + "composite": false, + "clientRole": true, + "containerId": "9a451e5c-a55a-4872-bee1-58af763101a1", + "attributes": {} + }, + { + "id": "f0370bc0-15d6-43f1-82bc-7d31f37b19e4", + "name": "manage-events", + "description": "${role_manage-events}", + "composite": false, + "clientRole": true, + "containerId": "9a451e5c-a55a-4872-bee1-58af763101a1", + "attributes": {} + }, + { + "id": "f0448680-b803-471e-8d0a-ec3e34a24228", + "name": "view-realm", + "description": "${role_view-realm}", + "composite": false, + "clientRole": true, + "containerId": "9a451e5c-a55a-4872-bee1-58af763101a1", + "attributes": {} + }, + { + "id": "dfdf768b-ac34-4491-b5d2-0938242e7e48", + "name": "query-groups", + "description": "${role_query-groups}", + "composite": false, + "clientRole": true, + "containerId": "9a451e5c-a55a-4872-bee1-58af763101a1", + "attributes": {} + }, + { + "id": "d5ff044b-c4e0-4197-8f51-833e8a956396", + "name": "query-clients", + "description": "${role_query-clients}", + "composite": false, + "clientRole": true, + "containerId": "9a451e5c-a55a-4872-bee1-58af763101a1", + "attributes": {} + }, + { + "id": "aaf73aa0-52a3-4833-8521-1eb1312b9f33", + "name": "manage-identity-providers", + "description": "${role_manage-identity-providers}", + "composite": false, + "clientRole": true, + "containerId": "9a451e5c-a55a-4872-bee1-58af763101a1", + "attributes": {} + }, + { + "id": "fa08c54a-1f0c-4392-bf6a-a698bf3d164b", + "name": "view-users", + "description": "${role_view-users}", + "composite": true, + "composites": { + "client": { + "master-realm": [ + "query-groups", + "query-users" + ] + } + }, + "clientRole": true, + "containerId": "9a451e5c-a55a-4872-bee1-58af763101a1", + "attributes": {} + }, + { + "id": "fd317e90-0b34-4263-8906-caa9d6000b28", + "name": "manage-clients", + "description": "${role_manage-clients}", + "composite": false, + "clientRole": true, + "containerId": "9a451e5c-a55a-4872-bee1-58af763101a1", + "attributes": {} + }, + { + "id": "162f12db-6d7f-4c53-905c-3f4bbd80fd58", + "name": "view-clients", + "description": "${role_view-clients}", + "composite": true, + "composites": { + "client": { + "master-realm": [ + "query-clients" + ] + } + }, + "clientRole": true, + "containerId": "9a451e5c-a55a-4872-bee1-58af763101a1", + "attributes": {} + } + ], + "account": [ + { + "id": "50c2778e-15fa-4c14-9414-5937649eb89f", + "name": "delete-account", + "description": "${role_delete-account}", + "composite": false, + "clientRole": true, + "containerId": "b63c04db-23a8-432b-a6a7-1a4c9a5d1cad", + "attributes": {} + }, + { + "id": "083c3506-866a-4b85-ae57-bab1c29ac33e", + "name": "view-groups", + "description": "${role_view-groups}", + "composite": false, + "clientRole": true, + "containerId": "b63c04db-23a8-432b-a6a7-1a4c9a5d1cad", + "attributes": {} + }, + { + "id": "a1942880-1a32-402c-b9bb-e8f5edf2ba1a", + "name": "view-profile", + "description": "${role_view-profile}", + "composite": false, + "clientRole": true, + "containerId": "b63c04db-23a8-432b-a6a7-1a4c9a5d1cad", + "attributes": {} + }, + { + "id": "a69f73d6-ce42-41e6-b341-30a2d99caba8", + "name": "manage-account-links", + "description": "${role_manage-account-links}", + "composite": false, + "clientRole": true, + "containerId": "b63c04db-23a8-432b-a6a7-1a4c9a5d1cad", + "attributes": {} + }, + { + "id": "ac22aeec-062a-4fc0-ac79-aa849ee55d84", + "name": "manage-consent", + "description": "${role_manage-consent}", + "composite": true, + "composites": { + "client": { + "account": [ + "view-consent" + ] + } + }, + "clientRole": true, + "containerId": "b63c04db-23a8-432b-a6a7-1a4c9a5d1cad", + "attributes": {} + }, + { + "id": "ad45329d-0efa-4505-906a-5a69b6c8414a", + "name": "view-applications", + "description": "${role_view-applications}", + "composite": false, + "clientRole": true, + "containerId": "b63c04db-23a8-432b-a6a7-1a4c9a5d1cad", + "attributes": {} + }, + { + "id": "8c0bfbdf-1914-4522-9024-ef0e6e91be9d", + "name": "view-consent", + "description": "${role_view-consent}", + "composite": false, + "clientRole": true, + "containerId": "b63c04db-23a8-432b-a6a7-1a4c9a5d1cad", + "attributes": {} + }, + { + "id": "f34de6ff-a5aa-41a7-a8d2-87bdfa850c50", + "name": "manage-account", + "description": "${role_manage-account}", + "composite": true, + "composites": { + "client": { + "account": [ + "manage-account-links" + ] + } + }, + "clientRole": true, + "containerId": "b63c04db-23a8-432b-a6a7-1a4c9a5d1cad", + "attributes": {} + } + ], + "dbrepo-realm": [ + { + "id": "89292ccf-3b12-4c8b-a615-966ddcf14556", + "name": "manage-users", + "description": "${role_manage-users}", + "composite": false, + "clientRole": true, + "containerId": "c10597a2-3888-43c4-9d60-1a90a6a4d490", + "attributes": {} + }, + { + "id": "784f2fdf-a090-4452-8a02-d9cc8227df8f", + "name": "view-authorization", + "description": "${role_view-authorization}", + "composite": false, + "clientRole": true, + "containerId": "c10597a2-3888-43c4-9d60-1a90a6a4d490", + "attributes": {} + }, + { + "id": "57a70a96-bc56-4629-8d2b-86c68ac1c6f6", + "name": "query-realms", + "description": "${role_query-realms}", + "composite": false, + "clientRole": true, + "containerId": "c10597a2-3888-43c4-9d60-1a90a6a4d490", + "attributes": {} + }, + { + "id": "60349d70-ba29-426d-9c05-df0b11e1a73b", + "name": "query-clients", + "description": "${role_query-clients}", + "composite": false, + "clientRole": true, + "containerId": "c10597a2-3888-43c4-9d60-1a90a6a4d490", + "attributes": {} + }, + { + "id": "c07819ae-8951-4dc4-af4d-bca93c60eb5a", + "name": "view-identity-providers", + "description": "${role_view-identity-providers}", + "composite": false, + "clientRole": true, + "containerId": "c10597a2-3888-43c4-9d60-1a90a6a4d490", + "attributes": {} + }, + { + "id": "86842bf0-7f63-4053-8389-2ec5401cb2a9", + "name": "query-groups", + "description": "${role_query-groups}", + "composite": false, + "clientRole": true, + "containerId": "c10597a2-3888-43c4-9d60-1a90a6a4d490", + "attributes": {} + }, + { + "id": "0a1579a0-76c5-4ee3-90cc-c924827b7492", + "name": "view-realm", + "description": "${role_view-realm}", + "composite": false, + "clientRole": true, + "containerId": "c10597a2-3888-43c4-9d60-1a90a6a4d490", + "attributes": {} + }, + { + "id": "4eb0d05c-38c7-4d45-b858-ad7011df0ac0", + "name": "manage-identity-providers", + "description": "${role_manage-identity-providers}", + "composite": false, + "clientRole": true, + "containerId": "c10597a2-3888-43c4-9d60-1a90a6a4d490", + "attributes": {} + }, + { + "id": "d4ff5a03-21e8-440c-9ccb-690ecbb89684", + "name": "manage-events", + "description": "${role_manage-events}", + "composite": false, + "clientRole": true, + "containerId": "c10597a2-3888-43c4-9d60-1a90a6a4d490", + "attributes": {} + }, + { + "id": "00d523c3-e9c7-45c3-8221-0b6d6c82cd5d", + "name": "manage-authorization", + "description": "${role_manage-authorization}", + "composite": false, + "clientRole": true, + "containerId": "c10597a2-3888-43c4-9d60-1a90a6a4d490", + "attributes": {} + }, + { + "id": "c441f018-7113-4fcb-8208-10ab4bd4bb27", + "name": "view-clients", + "description": "${role_view-clients}", + "composite": true, + "composites": { + "client": { + "dbrepo-realm": [ + "query-clients" + ] + } + }, + "clientRole": true, + "containerId": "c10597a2-3888-43c4-9d60-1a90a6a4d490", + "attributes": {} + }, + { + "id": "a146533f-fbf3-4513-8505-cf44473f5459", + "name": "create-client", + "description": "${role_create-client}", + "composite": false, + "clientRole": true, + "containerId": "c10597a2-3888-43c4-9d60-1a90a6a4d490", + "attributes": {} + }, + { + "id": "d3d0ed01-05a5-4812-8fa7-9231f71e61fa", + "name": "query-users", + "description": "${role_query-users}", + "composite": false, + "clientRole": true, + "containerId": "c10597a2-3888-43c4-9d60-1a90a6a4d490", + "attributes": {} + }, + { + "id": "fcaed53d-022a-416d-b207-a6ae694a9384", + "name": "manage-clients", + "description": "${role_manage-clients}", + "composite": false, + "clientRole": true, + "containerId": "c10597a2-3888-43c4-9d60-1a90a6a4d490", + "attributes": {} + }, + { + "id": "cefdb023-0eec-4c05-93d7-8b557bb28a81", + "name": "view-users", + "description": "${role_view-users}", + "composite": true, + "composites": { + "client": { + "dbrepo-realm": [ + "query-users", + "query-groups" + ] + } + }, + "clientRole": true, + "containerId": "c10597a2-3888-43c4-9d60-1a90a6a4d490", + "attributes": {} + }, + { + "id": "44d13b2a-a2b5-4f3b-bea1-4ab550205e12", + "name": "manage-realm", + "description": "${role_manage-realm}", + "composite": false, + "clientRole": true, + "containerId": "c10597a2-3888-43c4-9d60-1a90a6a4d490", + "attributes": {} + }, + { + "id": "17378e7a-9a78-4e92-ae0b-6bdfadede2d5", + "name": "impersonation", + "description": "${role_impersonation}", + "composite": false, + "clientRole": true, + "containerId": "c10597a2-3888-43c4-9d60-1a90a6a4d490", + "attributes": {} + }, + { + "id": "7810ab39-c546-456c-81eb-7ee09492da92", + "name": "view-events", + "description": "${role_view-events}", + "composite": false, + "clientRole": true, + "containerId": "c10597a2-3888-43c4-9d60-1a90a6a4d490", + "attributes": {} + } + ] + } + }, + "groups": [ + { + "id": "1fcdbec1-9c86-4a14-a859-425b43cf73cb", + "name": "system", + "path": "/system", + "subGroups": [], + "attributes": {}, + "realmRoles": [ + "default-roles-master", + "default-system-roles", + "admin", + "create-realm" + ], + "clientRoles": {} + } + ], + "defaultRole": { + "id": "01178d3c-65eb-406b-87a1-e7144f488028", + "name": "default-roles-master", + "description": "${role_default-roles}", + "composite": true, + "clientRole": false, + "containerId": "afe47bd0-61f8-40c3-95cb-04930407ebdd" + }, + "requiredCredentials": [ + "password" + ], + "otpPolicyType": "totp", + "otpPolicyAlgorithm": "HmacSHA1", + "otpPolicyInitialCounter": 0, + "otpPolicyDigits": 6, + "otpPolicyLookAheadWindow": 1, + "otpPolicyPeriod": 30, + "otpPolicyCodeReusable": false, + "otpSupportedApplications": [ + "totpAppFreeOTPName", + "totpAppGoogleName", + "totpAppMicrosoftAuthenticatorName" + ], + "localizationTexts": {}, + "webAuthnPolicyRpEntityName": "keycloak", + "webAuthnPolicySignatureAlgorithms": [ + "ES256", + "RS256" + ], + "webAuthnPolicyRpId": "", + "webAuthnPolicyAttestationConveyancePreference": "not specified", + "webAuthnPolicyAuthenticatorAttachment": "not specified", + "webAuthnPolicyRequireResidentKey": "not specified", + "webAuthnPolicyUserVerificationRequirement": "not specified", + "webAuthnPolicyCreateTimeout": 0, + "webAuthnPolicyAvoidSameAuthenticatorRegister": false, + "webAuthnPolicyAcceptableAaguids": [], + "webAuthnPolicyExtraOrigins": [], + "webAuthnPolicyPasswordlessRpEntityName": "keycloak", + "webAuthnPolicyPasswordlessSignatureAlgorithms": [ + "ES256", + "RS256" + ], + "webAuthnPolicyPasswordlessRpId": "", + "webAuthnPolicyPasswordlessAttestationConveyancePreference": "not specified", + "webAuthnPolicyPasswordlessAuthenticatorAttachment": "not specified", + "webAuthnPolicyPasswordlessRequireResidentKey": "not specified", + "webAuthnPolicyPasswordlessUserVerificationRequirement": "not specified", + "webAuthnPolicyPasswordlessCreateTimeout": 0, + "webAuthnPolicyPasswordlessAvoidSameAuthenticatorRegister": false, + "webAuthnPolicyPasswordlessAcceptableAaguids": [], + "webAuthnPolicyPasswordlessExtraOrigins": [], + "scopeMappings": [ + { + "clientScope": "offline_access", + "roles": [ + "offline_access" + ] + } + ], + "clientScopeMappings": { + "account": [ + { + "client": "account-console", + "roles": [ + "manage-account", + "view-groups" + ] + } + ] + }, + "clients": [ + { + "id": "b63c04db-23a8-432b-a6a7-1a4c9a5d1cad", + "clientId": "account", + "name": "${client_account}", + "rootUrl": "${authBaseUrl}", + "baseUrl": "/realms/master/account/", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [ + "/realms/master/account/*" + ], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "realm_client": "false", + "post.logout.redirect.uris": "+" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": [ + "web-origins", + "acr", + "roles", + "profile", + "basic", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "organization", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "1af255f9-7eee-415c-9096-3a717d2c5150", + "clientId": "account-console", + "name": "${client_account-console}", + "rootUrl": "${authBaseUrl}", + "baseUrl": "/realms/master/account/", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [ + "/realms/master/account/*" + ], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "realm_client": "false", + "post.logout.redirect.uris": "+", + "pkce.code.challenge.method": "S256" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "protocolMappers": [ + { + "id": "63d1e47d-6e61-4f36-8a5b-98384a782d60", + "name": "audience resolve", + "protocol": "openid-connect", + "protocolMapper": "oidc-audience-resolve-mapper", + "consentRequired": false, + "config": {} + } + ], + "defaultClientScopes": [ + "web-origins", + "acr", + "roles", + "profile", + "basic", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "organization", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "65ce3e14-5e30-424a-a6bd-0b194da203ef", + "clientId": "admin-cli", + "name": "${client_admin-cli}", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": false, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": true, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "realm_client": "false", + "client.use.lightweight.access.token.enabled": "true", + "post.logout.redirect.uris": "+" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": true, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": [ + "web-origins", + "acr", + "roles", + "profile", + "basic", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "organization", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "217563ea-11c7-4c96-969b-af076d740f7c", + "clientId": "broker", + "name": "${client_broker}", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": true, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": false, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "realm_client": "true", + "post.logout.redirect.uris": "+" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": [ + "web-origins", + "acr", + "roles", + "profile", + "basic", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "organization", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "c10597a2-3888-43c4-9d60-1a90a6a4d490", + "clientId": "dbrepo-realm", + "name": "dbrepo Realm", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": true, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": false, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "realm_client": "true", + "post.logout.redirect.uris": "+" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": [], + "optionalClientScopes": [] + }, + { + "id": "9a451e5c-a55a-4872-bee1-58af763101a1", + "clientId": "master-realm", + "name": "master Realm", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": true, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": false, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "realm_client": "true", + "post.logout.redirect.uris": "+" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": [ + "web-origins", + "acr", + "roles", + "profile", + "basic", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "organization", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "b2a24dc7-01d2-4a5a-8385-8b06d2b8a3fb", + "clientId": "security-admin-console", + "name": "${client_security-admin-console}", + "rootUrl": "${authAdminUrl}", + "baseUrl": "/admin/master/console/", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [ + "/admin/master/console/*" + ], + "webOrigins": [ + "+" + ], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "realm_client": "false", + "client.use.lightweight.access.token.enabled": "true", + "post.logout.redirect.uris": "+", + "pkce.code.challenge.method": "S256" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": true, + "nodeReRegistrationTimeout": 0, + "protocolMappers": [ + { + "id": "54d1c74b-4eb6-483b-88b5-261964dd182a", + "name": "locale", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "locale", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "locale", + "jsonType.label": "String" + } + } + ], + "defaultClientScopes": [ + "web-origins", + "acr", + "roles", + "profile", + "basic", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "organization", + "offline_access", + "microprofile-jwt" + ] + } + ], + "clientScopes": [ + { + "id": "12ce4fa5-b53e-47dc-b70f-caf2110e31cd", + "name": "address", + "description": "OpenID Connect built-in scope: address", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "consent.screen.text": "${addressScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "4aed5e41-0d8d-4c24-80a0-cd9822072756", + "name": "address", + "protocol": "openid-connect", + "protocolMapper": "oidc-address-mapper", + "consentRequired": false, + "config": { + "user.attribute.formatted": "formatted", + "user.attribute.country": "country", + "introspection.token.claim": "true", + "user.attribute.postal_code": "postal_code", + "userinfo.token.claim": "true", + "user.attribute.street": "street", + "id.token.claim": "true", + "user.attribute.region": "region", + "access.token.claim": "true", + "user.attribute.locality": "locality" + } + } + ] + }, + { + "id": "a7683fe7-1c8b-44f8-9be7-a28acdffa61e", + "name": "organization", + "description": "Additional claims about the organization a subject belongs to", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "consent.screen.text": "${organizationScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "5e80a7d2-c9d0-48e1-aadc-d8848ff90f92", + "name": "organization", + "protocol": "openid-connect", + "protocolMapper": "oidc-organization-membership-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "multivalued": "true", + "userinfo.token.claim": "true", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "organization", + "jsonType.label": "String" + } + } + ] + }, + { + "id": "0411ea86-a074-4781-850d-ea3ca94590a2", + "name": "offline_access", + "description": "OpenID Connect built-in scope: offline_access", + "protocol": "openid-connect", + "attributes": { + "consent.screen.text": "${offlineAccessScopeConsentText}", + "display.on.consent.screen": "true" + } + }, + { + "id": "4363ea0f-c7e9-43f3-8611-146514c37b47", + "name": "basic", + "description": "OpenID Connect scope for add all basic claims to the token", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "display.on.consent.screen": "false" + }, + "protocolMappers": [ + { + "id": "0b691845-92b7-47b8-82d3-6fea760d885a", + "name": "sub", + "protocol": "openid-connect", + "protocolMapper": "oidc-sub-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "access.token.claim": "true" + } + }, + { + "id": "15db8f91-12c9-444c-8661-5a795856e884", + "name": "auth_time", + "protocol": "openid-connect", + "protocolMapper": "oidc-usersessionmodel-note-mapper", + "consentRequired": false, + "config": { + "user.session.note": "AUTH_TIME", + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "auth_time", + "jsonType.label": "long" + } + } + ] + }, + { + "id": "5f9da2a4-b8d2-48cd-9343-5c8ff42ef637", + "name": "profile", + "description": "OpenID Connect built-in scope: profile", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "consent.screen.text": "${profileScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "2d1400be-4053-4393-ba87-91b64f699054", + "name": "full name", + "protocol": "openid-connect", + "protocolMapper": "oidc-full-name-mapper", + "consentRequired": false, + "config": { + "id.token.claim": "true", + "introspection.token.claim": "true", + "access.token.claim": "true", + "userinfo.token.claim": "true" + } + }, + { + "id": "6b12336d-589e-4023-9c51-1da3a4114a62", + "name": "website", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "website", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "website", + "jsonType.label": "String" + } + }, + { + "id": "13a7a453-3862-40b4-8a81-550172a06dc0", + "name": "zoneinfo", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "zoneinfo", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "zoneinfo", + "jsonType.label": "String" + } + }, + { + "id": "43c149fc-aaf4-486a-a279-df624d2eb47e", + "name": "given name", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "firstName", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "given_name", + "jsonType.label": "String" + } + }, + { + "id": "8bba390c-543b-4fe3-98db-e020184e5014", + "name": "birthdate", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "birthdate", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "birthdate", + "jsonType.label": "String" + } + }, + { + "id": "dc5a7474-c62a-42d6-ba98-f2b2a7a7328c", + "name": "nickname", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "nickname", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "nickname", + "jsonType.label": "String" + } + }, + { + "id": "9e02395e-5c37-46fb-8d30-0ebe6da3b7f0", + "name": "gender", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "gender", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "gender", + "jsonType.label": "String" + } + }, + { + "id": "d2f3d16d-21a8-4128-b60b-55e55046fa29", + "name": "profile", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "profile", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "profile", + "jsonType.label": "String" + } + }, + { + "id": "825cafb6-3392-491a-bb34-e607330f5170", + "name": "family name", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "lastName", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "family_name", + "jsonType.label": "String" + } + }, + { + "id": "c44ac799-cac2-4200-b71b-badab4b48d92", + "name": "updated at", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "updatedAt", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "updated_at", + "jsonType.label": "long" + } + }, + { + "id": "402b2c5f-0a7b-4520-9015-03fa9a1e2e4a", + "name": "picture", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "picture", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "picture", + "jsonType.label": "String" + } + }, + { + "id": "f34812b0-28b3-486c-8911-9394890be4f6", + "name": "locale", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "locale", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "locale", + "jsonType.label": "String" + } + }, + { + "id": "3fe6f4f2-c881-4b84-87db-8e9b9243a7f0", + "name": "middle name", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "middleName", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "middle_name", + "jsonType.label": "String" + } + }, + { + "id": "4d1465b2-c408-4a62-9821-afce35a55f12", + "name": "username", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "username", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "preferred_username", + "jsonType.label": "String" + } + } + ] + }, + { + "id": "9b03908f-dac3-4bbd-8e93-ef29e64a59ad", + "name": "role_list", + "description": "SAML role list", + "protocol": "saml", + "attributes": { + "consent.screen.text": "${samlRoleListScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "d6678801-a0f1-4385-ae11-5dee90a9e3b4", + "name": "role list", + "protocol": "saml", + "protocolMapper": "saml-role-list-mapper", + "consentRequired": false, + "config": { + "single": "false", + "attribute.nameformat": "Basic", + "attribute.name": "Role" + } + } + ] + }, + { + "id": "fa13fc44-16f6-4f82-965d-b86dfad2a984", + "name": "microprofile-jwt", + "description": "Microprofile - JWT built-in scope", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "false" + }, + "protocolMappers": [ + { + "id": "f70938d7-e91f-4c45-bfed-3b974d0e4697", + "name": "groups", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-realm-role-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "multivalued": "true", + "userinfo.token.claim": "true", + "user.attribute": "foo", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "groups", + "jsonType.label": "String" + } + }, + { + "id": "1636d5e3-2af1-4d54-a60f-9db1f562b009", + "name": "upn", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "username", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "upn", + "jsonType.label": "String" + } + } + ] + }, + { + "id": "1124b695-1319-45aa-bc1b-ec0b2cf99b9e", + "name": "acr", + "description": "OpenID Connect scope for add acr (authentication context class reference) to the token", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "display.on.consent.screen": "false" + }, + "protocolMappers": [ + { + "id": "0e17d8d7-fb11-4b31-8023-d29611f7d492", + "name": "acr loa level", + "protocol": "openid-connect", + "protocolMapper": "oidc-acr-mapper", + "consentRequired": false, + "config": { + "id.token.claim": "true", + "introspection.token.claim": "true", + "access.token.claim": "true", + "userinfo.token.claim": "true" + } + } + ] + }, + { + "id": "cc53d998-1eac-4574-9bec-58110d92d282", + "name": "web-origins", + "description": "OpenID Connect scope for add allowed web origins to the access token", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "consent.screen.text": "", + "display.on.consent.screen": "false" + }, + "protocolMappers": [ + { + "id": "635cbac1-7cab-43bd-99fc-f7084aca2fa2", + "name": "allowed web origins", + "protocol": "openid-connect", + "protocolMapper": "oidc-allowed-origins-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "access.token.claim": "true" + } + } + ] + }, + { + "id": "2c901d49-bb6d-44a7-8835-1229b655ccfa", + "name": "saml_organization", + "description": "Organization Membership", + "protocol": "saml", + "attributes": { + "display.on.consent.screen": "false" + }, + "protocolMappers": [ + { + "id": "60ad6a87-646d-4c9e-932e-34ab1ac51fcb", + "name": "organization", + "protocol": "saml", + "protocolMapper": "saml-organization-membership-mapper", + "consentRequired": false, + "config": {} + } + ] + }, + { + "id": "943d1441-ee61-4ab5-b5bd-de3c5f8ff25f", + "name": "roles", + "description": "OpenID Connect scope for add user roles to the access token", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "consent.screen.text": "${rolesScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "2b5a3df4-1adb-402d-bc28-2bd43224e682", + "name": "realm roles", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-realm-role-mapper", + "consentRequired": false, + "config": { + "user.attribute": "foo", + "introspection.token.claim": "true", + "access.token.claim": "true", + "claim.name": "realm_access.roles", + "jsonType.label": "String", + "multivalued": "true" + } + }, + { + "id": "f3b60071-ef26-48a7-9554-67f62f84d543", + "name": "client roles", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-client-role-mapper", + "consentRequired": false, + "config": { + "user.attribute": "foo", + "introspection.token.claim": "true", + "access.token.claim": "true", + "claim.name": "resource_access.${client_id}.roles", + "jsonType.label": "String", + "multivalued": "true" + } + }, + { + "id": "b757200e-494a-4585-857e-e4c18aef7a0c", + "name": "audience resolve", + "protocol": "openid-connect", + "protocolMapper": "oidc-audience-resolve-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "access.token.claim": "true" + } + } + ] + }, + { + "id": "4509fb3c-a899-49ad-b690-b031f9568888", + "name": "email", + "description": "OpenID Connect built-in scope: email", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "consent.screen.text": "${emailScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "e18769b3-778b-47d8-be52-dd2769deebd1", + "name": "email", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "email", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "email", + "jsonType.label": "String" + } + }, + { + "id": "d98c5037-5178-4cc5-8e22-ca6cf0cb169e", + "name": "email verified", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "emailVerified", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "email_verified", + "jsonType.label": "boolean" + } + } + ] + }, + { + "id": "6e14db34-285a-47ae-8b43-b3dcf10ae7f8", + "name": "phone", + "description": "OpenID Connect built-in scope: phone", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "consent.screen.text": "${phoneScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "98cc724c-3f53-47f7-bf9f-baf2f7e08026", + "name": "phone number verified", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "phoneNumberVerified", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "phone_number_verified", + "jsonType.label": "boolean" + } + }, + { + "id": "716a7b58-dcf4-4557-9f84-d21ca19630fb", + "name": "phone number", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "phoneNumber", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "phone_number", + "jsonType.label": "String" + } + } + ] + } + ], + "defaultDefaultClientScopes": [ + "role_list", + "saml_organization", + "profile", + "email", + "roles", + "web-origins", + "acr", + "basic" + ], + "defaultOptionalClientScopes": [ + "offline_access", + "address", + "phone", + "microprofile-jwt", + "organization" + ], + "browserSecurityHeaders": { + "contentSecurityPolicyReportOnly": "", + "xContentTypeOptions": "nosniff", + "referrerPolicy": "no-referrer", + "xRobotsTag": "none", + "xFrameOptions": "SAMEORIGIN", + "contentSecurityPolicy": "frame-src 'self'; frame-ancestors 'self'; object-src 'none';", + "xXSSProtection": "1; mode=block", + "strictTransportSecurity": "max-age=31536000; includeSubDomains" + }, + "smtpServer": {}, + "eventsEnabled": false, + "eventsListeners": [ + "jboss-logging" + ], + "enabledEventTypes": [], + "adminEventsEnabled": false, + "adminEventsDetailsEnabled": false, + "identityProviders": [], + "identityProviderMappers": [], + "components": { + "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy": [ + { + "id": "f2a52e27-5582-4ca4-b20c-1864b8339b16", + "name": "Trusted Hosts", + "providerId": "trusted-hosts", + "subType": "anonymous", + "subComponents": {}, + "config": { + "host-sending-registration-request-must-match": [ + "true" + ], + "client-uris-must-match": [ + "true" + ] + } + }, + { + "id": "95b33704-ec30-4988-b018-f73d8bcf71b5", + "name": "Full Scope Disabled", + "providerId": "scope", + "subType": "anonymous", + "subComponents": {}, + "config": {} + }, + { + "id": "d1114c75-d0b0-4584-a89f-a4e70eab2cd7", + "name": "Consent Required", + "providerId": "consent-required", + "subType": "anonymous", + "subComponents": {}, + "config": {} + }, + { + "id": "6b0202cc-e70e-46da-869b-36ad59907239", + "name": "Allowed Protocol Mapper Types", + "providerId": "allowed-protocol-mappers", + "subType": "anonymous", + "subComponents": {}, + "config": { + "allowed-protocol-mapper-types": [ + "oidc-usermodel-attribute-mapper", + "saml-role-list-mapper", + "oidc-sha256-pairwise-sub-mapper", + "oidc-usermodel-property-mapper", + "saml-user-attribute-mapper", + "oidc-full-name-mapper", + "oidc-address-mapper", + "saml-user-property-mapper" + ] + } + }, + { + "id": "4b976576-c880-48a0-9b4d-2956cfd19b4a", + "name": "Allowed Protocol Mapper Types", + "providerId": "allowed-protocol-mappers", + "subType": "authenticated", + "subComponents": {}, + "config": { + "allowed-protocol-mapper-types": [ + "saml-role-list-mapper", + "oidc-usermodel-property-mapper", + "oidc-full-name-mapper", + "saml-user-attribute-mapper", + "saml-user-property-mapper", + "oidc-address-mapper", + "oidc-sha256-pairwise-sub-mapper", + "oidc-usermodel-attribute-mapper" + ] + } + }, + { + "id": "e1861ec9-2761-46fb-8048-149492269ff0", + "name": "Allowed Client Scopes", + "providerId": "allowed-client-templates", + "subType": "anonymous", + "subComponents": {}, + "config": { + "allow-default-scopes": [ + "true" + ] + } + }, + { + "id": "51b3aa61-e453-4e0b-bfe1-aefd8353ea06", + "name": "Max Clients Limit", + "providerId": "max-clients", + "subType": "anonymous", + "subComponents": {}, + "config": { + "max-clients": [ + "200" + ] + } + }, + { + "id": "851cf8c2-ffe8-4a37-8a12-df04f724c90b", + "name": "Allowed Client Scopes", + "providerId": "allowed-client-templates", + "subType": "authenticated", + "subComponents": {}, + "config": { + "allow-default-scopes": [ + "true" + ] + } + } + ], + "org.keycloak.userprofile.UserProfileProvider": [ + { + "id": "34049725-5a66-456c-b895-87ca7c11bb6b", + "providerId": "declarative-user-profile", + "subComponents": {}, + "config": { + "kc.user.profile.config": [ + "{\"attributes\":[{\"name\":\"username\",\"displayName\":\"${username}\",\"validations\":{\"length\":{\"min\":3,\"max\":255},\"username-prohibited-characters\":{},\"up-username-not-idn-homograph\":{}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"email\",\"displayName\":\"${email}\",\"validations\":{\"email\":{},\"length\":{\"max\":255}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"firstName\",\"displayName\":\"${firstName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"lastName\",\"displayName\":\"${lastName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false}],\"groups\":[{\"name\":\"user-metadata\",\"displayHeader\":\"User metadata\",\"displayDescription\":\"Attributes, which refer to user metadata\"}]}" + ] + } + } + ], + "org.keycloak.storage.UserStorageProvider": [ + { + "id": "3a6f24e8-128b-4ac1-b3ab-694836db82fd", + "name": "Identity Service", + "providerId": "ldap", + "subComponents": { + "org.keycloak.storage.ldap.mappers.LDAPStorageMapper": [ + { + "id": "bf97cfab-4d53-4994-b3a8-0c771a70467b", + "name": "email", + "providerId": "user-attribute-ldap-mapper", + "subComponents": {}, + "config": { + "ldap.attribute": [ + "mail" + ], + "is.mandatory.in.ldap": [ + "false" + ], + "always.read.value.from.ldap": [ + "false" + ], + "read.only": [ + "false" + ], + "user.model.attribute": [ + "email" + ] + } + }, + { + "id": "cddffa16-0aff-4e0c-99a2-021f0495de03", + "name": "last name", + "providerId": "user-attribute-ldap-mapper", + "subComponents": {}, + "config": { + "ldap.attribute": [ + "sn" + ], + "is.mandatory.in.ldap": [ + "true" + ], + "always.read.value.from.ldap": [ + "true" + ], + "read.only": [ + "false" + ], + "user.model.attribute": [ + "lastName" + ] + } + }, + { + "id": "4eaae3fa-d280-4605-b09d-1caeb881322c", + "name": "modify date", + "providerId": "user-attribute-ldap-mapper", + "subComponents": {}, + "config": { + "ldap.attribute": [ + "modifyTimestamp" + ], + "is.mandatory.in.ldap": [ + "false" + ], + "always.read.value.from.ldap": [ + "true" + ], + "read.only": [ + "true" + ], + "user.model.attribute": [ + "modifyTimestamp" + ] + } + }, + { + "id": "98c4a2c1-d509-443b-8475-fc971c193324", + "name": "first name", + "providerId": "user-attribute-ldap-mapper", + "subComponents": {}, + "config": { + "ldap.attribute": [ + "cn" + ], + "is.mandatory.in.ldap": [ + "true" + ], + "read.only": [ + "false" + ], + "always.read.value.from.ldap": [ + "true" + ], + "user.model.attribute": [ + "firstName" + ] + } + }, + { + "id": "74dbebb4-9881-4be1-8b30-6b0f2a718c86", + "name": "username", + "providerId": "user-attribute-ldap-mapper", + "subComponents": {}, + "config": { + "ldap.attribute": [ + "uid" + ], + "is.mandatory.in.ldap": [ + "true" + ], + "always.read.value.from.ldap": [ + "false" + ], + "read.only": [ + "false" + ], + "user.model.attribute": [ + "username" + ] + } + }, + { + "id": "5692d060-55b8-4cb1-b68f-0ae123cd9d03", + "name": "system", + "providerId": "group-ldap-mapper", + "subComponents": {}, + "config": { + "mode": [ + "LDAP_ONLY" + ], + "membership.attribute.type": [ + "DN" + ], + "user.roles.retrieve.strategy": [ + "LOAD_GROUPS_BY_MEMBER_ATTRIBUTE" + ], + "group.name.ldap.attribute": [ + "cn" + ], + "membership.ldap.attribute": [ + "member" + ], + "membership.user.ldap.attribute": [ + "uid" + ], + "ignore.missing.groups": [ + "false" + ], + "preserve.group.inheritance": [ + "false" + ], + "groups.dn": [ + "ou=users,dc=dbrepo,dc=at" + ], + "memberof.ldap.attribute": [ + "memberOf" + ], + "group.object.classes": [ + "groupOfNames" + ], + "drop.non.existing.groups.during.sync": [ + "false" + ], + "groups.path": [ + "/" + ] + } + }, + { + "id": "0453ae29-3cdc-4e09-800e-0117e7a2fb68", + "name": "creation date", + "providerId": "user-attribute-ldap-mapper", + "subComponents": {}, + "config": { + "ldap.attribute": [ + "createTimestamp" + ], + "is.mandatory.in.ldap": [ + "false" + ], + "always.read.value.from.ldap": [ + "true" + ], + "read.only": [ + "true" + ], + "user.model.attribute": [ + "createTimestamp" + ] + } + } + ] + }, + "config": { + "pagination": [ + "false" + ], + "fullSyncPeriod": [ + "-1" + ], + "startTls": [ + "false" + ], + "connectionPooling": [ + "false" + ], + "usersDn": [ + "ou=users,dc=dbrepo,dc=at" + ], + "cachePolicy": [ + "DEFAULT" + ], + "useKerberosForPasswordAuthentication": [ + "false" + ], + "importEnabled": [ + "true" + ], + "enabled": [ + "true" + ], + "changedSyncPeriod": [ + "-1" + ], + "usernameLDAPAttribute": [ + "uid" + ], + "bindCredential": [ + "admin" + ], + "bindDn": [ + "cn=admin,dc=dbrepo,dc=at" + ], + "vendor": [ + "other" + ], + "uuidLDAPAttribute": [ + "entryUUID" + ], + "allowKerberosAuthentication": [ + "false" + ], + "connectionUrl": [ + "ldap://identity-service:1389" + ], + "syncRegistrations": [ + "true" + ], + "authType": [ + "simple" + ], + "krbPrincipalAttribute": [ + "krb5PrincipalName" + ], + "searchScope": [ + "1" + ], + "useTruststoreSpi": [ + "always" + ], + "usePasswordModifyExtendedOp": [ + "false" + ], + "trustEmail": [ + "false" + ], + "userObjectClasses": [ + "inetOrgPerson, organizationalPerson, person" + ], + "rdnLDAPAttribute": [ + "uid" + ], + "editMode": [ + "READ_ONLY" + ], + "validatePasswordPolicy": [ + "false" + ] + } + } + ], + "org.keycloak.keys.KeyProvider": [ + { + "id": "5b1052d2-fb71-47d2-86f9-908c869c8d1b", + "name": "hmac-generated-hs512", + "providerId": "hmac-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ], + "algorithm": [ + "HS512" + ] + } + }, + { + "id": "fd48cdb1-8be8-4ac9-9347-dc3e91db95d7", + "name": "rsa-enc-generated", + "providerId": "rsa-enc-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ], + "algorithm": [ + "RSA-OAEP" + ] + } + }, + { + "id": "0ff03eb6-b43b-4065-b583-9e310f53a573", + "name": "rsa-generated", + "providerId": "rsa-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ] + } + }, + { + "id": "df28b561-7463-4927-974d-615618056b41", + "name": "aes-generated", + "providerId": "aes-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ] + } + } + ] + }, + "internationalizationEnabled": false, + "supportedLocales": [], + "authenticationFlows": [ + { + "id": "2e13d5a8-b0fb-475b-8991-66d1cc8e99f1", + "alias": "Account verification options", + "description": "Method with which to verity the existing account", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "idp-email-verification", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "ALTERNATIVE", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Verify Existing Account by Re-authentication", + "userSetupAllowed": false + } + ] + }, + { + "id": "0bf3a099-5ef5-4ea9-b325-5bc9699180a6", + "alias": "Browser - Conditional OTP", + "description": "Flow to determine if the OTP is required for the authentication", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "auth-otp-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "88ca29ab-cbe0-4e3f-938a-e6c5327748ab", + "alias": "Direct Grant - Conditional OTP", + "description": "Flow to determine if the OTP is required for the authentication", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "direct-grant-validate-otp", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "789e7d43-bc05-44d2-8c09-de7fee9d56de", + "alias": "First broker login - Conditional OTP", + "description": "Flow to determine if the OTP is required for the authentication", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "auth-otp-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "ee145b84-2b30-438e-9cee-6fe90909af1a", + "alias": "Handle Existing Account", + "description": "Handle what to do if there is existing account with same email/username like authenticated identity provider", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "idp-confirm-link", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Account verification options", + "userSetupAllowed": false + } + ] + }, + { + "id": "853d891a-0009-443c-91c3-a7f1ad1dd0dc", + "alias": "Reset - Conditional OTP", + "description": "Flow to determine if the OTP should be reset or not. Set to REQUIRED to force.", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "reset-otp", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "d7f13a9b-a13c-4236-ae41-df8da7e5fa8d", + "alias": "User creation or linking", + "description": "Flow for the existing/non-existing user alternatives", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticatorConfig": "create unique user config", + "authenticator": "idp-create-user-if-unique", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "ALTERNATIVE", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Handle Existing Account", + "userSetupAllowed": false + } + ] + }, + { + "id": "3cb699ee-11d4-44be-878b-a183b9e96b59", + "alias": "Verify Existing Account by Re-authentication", + "description": "Reauthentication of existing account", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "idp-username-password-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "First broker login - Conditional OTP", + "userSetupAllowed": false + } + ] + }, + { + "id": "61d5a1e2-7074-41ad-97bf-e5c41c70989e", + "alias": "browser", + "description": "Browser based authentication", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "auth-cookie", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "auth-spnego", + "authenticatorFlow": false, + "requirement": "DISABLED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "identity-provider-redirector", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 25, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "ALTERNATIVE", + "priority": 30, + "autheticatorFlow": true, + "flowAlias": "forms", + "userSetupAllowed": false + } + ] + }, + { + "id": "21dabcf1-8817-4f2d-981a-13239e160b56", + "alias": "clients", + "description": "Base authentication for clients", + "providerId": "client-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "client-secret", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "client-jwt", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "client-secret-jwt", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 30, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "client-x509", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 40, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "a349aeb2-9373-47ec-9381-0c379df56c71", + "alias": "direct grant", + "description": "OpenID Connect Resource Owner Grant", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "direct-grant-validate-username", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "direct-grant-validate-password", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 30, + "autheticatorFlow": true, + "flowAlias": "Direct Grant - Conditional OTP", + "userSetupAllowed": false + } + ] + }, + { + "id": "39b3aa37-4ece-4e31-acbc-79889994713e", + "alias": "docker auth", + "description": "Used by Docker clients to authenticate against the IDP", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "docker-http-basic-authenticator", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "18561349-cc5e-4e5b-bcb2-979645118f96", + "alias": "first broker login", + "description": "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticatorConfig": "review profile config", + "authenticator": "idp-review-profile", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "User creation or linking", + "userSetupAllowed": false + } + ] + }, + { + "id": "9933f082-3d53-4575-b011-90e6933fb2a1", + "alias": "forms", + "description": "Username, password, otp and other auth forms.", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "auth-username-password-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Browser - Conditional OTP", + "userSetupAllowed": false + } + ] + }, + { + "id": "00285357-456a-4fd4-b449-ed25253e6364", + "alias": "registration", + "description": "Registration flow", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "registration-page-form", + "authenticatorFlow": true, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": true, + "flowAlias": "registration form", + "userSetupAllowed": false + } + ] + }, + { + "id": "b9131fa9-5614-42b4-8353-c6c15e66c2ce", + "alias": "registration form", + "description": "Registration form", + "providerId": "form-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "registration-user-creation", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "registration-password-action", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 50, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "registration-recaptcha-action", + "authenticatorFlow": false, + "requirement": "DISABLED", + "priority": 60, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "registration-terms-and-conditions", + "authenticatorFlow": false, + "requirement": "DISABLED", + "priority": 70, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "424642cc-3a71-4732-ba38-b737179ce37f", + "alias": "reset credentials", + "description": "Reset credentials for a user if they forgot their password or something", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "reset-credentials-choose-user", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "reset-credential-email", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "reset-password", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 30, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 40, + "autheticatorFlow": true, + "flowAlias": "Reset - Conditional OTP", + "userSetupAllowed": false + } + ] + }, + { + "id": "c8c9c4dc-a39d-4ba6-ad4b-9447a8125349", + "alias": "saml ecp", + "description": "SAML ECP Profile Authentication Flow", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "http-basic-authenticator", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + } + ], + "authenticatorConfig": [ + { + "id": "49d63952-ca6e-450c-a65f-70388169cb90", + "alias": "create unique user config", + "config": { + "require.password.update.after.registration": "false" + } + }, + { + "id": "5b4f58fc-aff7-4e12-8c48-40aeb3db1432", + "alias": "review profile config", + "config": { + "update.profile.on.first.login": "missing" + } + } + ], + "requiredActions": [ + { + "alias": "CONFIGURE_TOTP", + "name": "Configure OTP", + "providerId": "CONFIGURE_TOTP", + "enabled": true, + "defaultAction": false, + "priority": 10, + "config": {} + }, + { + "alias": "TERMS_AND_CONDITIONS", + "name": "Terms and Conditions", + "providerId": "TERMS_AND_CONDITIONS", + "enabled": false, + "defaultAction": false, + "priority": 20, + "config": {} + }, + { + "alias": "UPDATE_PASSWORD", + "name": "Update Password", + "providerId": "UPDATE_PASSWORD", + "enabled": true, + "defaultAction": false, + "priority": 30, + "config": {} + }, + { + "alias": "UPDATE_PROFILE", + "name": "Update Profile", + "providerId": "UPDATE_PROFILE", + "enabled": true, + "defaultAction": false, + "priority": 40, + "config": {} + }, + { + "alias": "VERIFY_EMAIL", + "name": "Verify Email", + "providerId": "VERIFY_EMAIL", + "enabled": true, + "defaultAction": false, + "priority": 50, + "config": {} + }, + { + "alias": "delete_account", + "name": "Delete Account", + "providerId": "delete_account", + "enabled": false, + "defaultAction": false, + "priority": 60, + "config": {} + }, + { + "alias": "webauthn-register", + "name": "Webauthn Register", + "providerId": "webauthn-register", + "enabled": true, + "defaultAction": false, + "priority": 70, + "config": {} + }, + { + "alias": "webauthn-register-passwordless", + "name": "Webauthn Register Passwordless", + "providerId": "webauthn-register-passwordless", + "enabled": true, + "defaultAction": false, + "priority": 80, + "config": {} + }, + { + "alias": "VERIFY_PROFILE", + "name": "Verify Profile", + "providerId": "VERIFY_PROFILE", + "enabled": true, + "defaultAction": false, + "priority": 90, + "config": {} + }, + { + "alias": "delete_credential", + "name": "Delete Credential", + "providerId": "delete_credential", + "enabled": true, + "defaultAction": false, + "priority": 100, + "config": {} + }, + { + "alias": "update_user_locale", + "name": "Update User Locale", + "providerId": "update_user_locale", + "enabled": true, + "defaultAction": false, + "priority": 1000, + "config": {} + } + ], + "browserFlow": "browser", + "registrationFlow": "registration", + "directGrantFlow": "direct grant", + "resetCredentialsFlow": "reset credentials", + "clientAuthenticationFlow": "clients", + "dockerAuthenticationFlow": "docker auth", + "firstBrokerLoginFlow": "first broker login", + "attributes": { + "cibaBackchannelTokenDeliveryMode": "poll", + "cibaAuthRequestedUserHint": "login_hint", + "clientOfflineSessionMaxLifespan": "0", + "oauth2DevicePollingInterval": "5", + "clientSessionIdleTimeout": "0", + "clientOfflineSessionIdleTimeout": "0", + "cibaInterval": "5", + "realmReusableOtpCode": "false", + "cibaExpiresIn": "120", + "oauth2DeviceCodeLifespan": "600", + "parRequestUriLifespan": "60", + "clientSessionMaxLifespan": "0", + "frontendUrl": "", + "organizationsEnabled": "false", + "acr.loa.map": "{}" + }, + "keycloakVersion": "26.0.0", + "userManagedAccessAllowed": false, + "organizationsEnabled": false, + "clientProfiles": { + "profiles": [] + }, + "clientPolicies": { + "policies": [] + } +} \ No newline at end of file diff --git a/dbrepo-auth-service/server.keystore b/dbrepo-auth-service/server.keystore deleted file mode 100644 index 9dcd5051210b5bd2f945a8325610684c8e0029a8..0000000000000000000000000000000000000000 Binary files a/dbrepo-auth-service/server.keystore and /dev/null differ diff --git a/dbrepo-broker-service/README.md b/dbrepo-broker-service/README.md index 95e5afaefdfc73751db6856526ca8c5e3a8f4c7c..6cff53bb912b21c916f30b2a07f6a7c90a76dc5a 100644 --- a/dbrepo-broker-service/README.md +++ b/dbrepo-broker-service/README.md @@ -1,5 +1,7 @@ # Broker Service +Supports MQTT v3, v4 and v5 (https://www.rabbitmq.com/blog/2023/07/21/mqtt5) + ## Advanced Config https://www.rabbitmq.com/docs/ldap \ No newline at end of file diff --git a/dbrepo-broker-service/advanced.config b/dbrepo-broker-service/advanced.config index 4445ea601954e5c93c32edeba1638135c5af5e59..584bcc52325e61a8d6019d2f092590bb7f989530 100644 --- a/dbrepo-broker-service/advanced.config +++ b/dbrepo-broker-service/advanced.config @@ -1,4 +1,9 @@ [ + { + rabbit, [ + {forced_feature_flags_on_init, [quorum_queue, mqtt_v5]} + ] + }, { rabbitmq_auth_backend_ldap, [ diff --git a/dbrepo-broker-service/enabled_plugins b/dbrepo-broker-service/enabled_plugins index 95f1c0014dd4ee232580adea29176756a25274ed..db0ae888499ea44c2dd7d40f5ac9c8fcc0ca0567 100644 --- a/dbrepo-broker-service/enabled_plugins +++ b/dbrepo-broker-service/enabled_plugins @@ -1 +1 @@ -[rabbitmq_prometheus,rabbitmq_auth_backend_ldap,rabbitmq_auth_mechanism_ssl,rabbitmq_management]. \ No newline at end of file +[rabbitmq_prometheus,rabbitmq_auth_backend_ldap,rabbitmq_auth_mechanism_ssl,rabbitmq_management,rabbitmq_mqtt]. \ No newline at end of file diff --git a/dbrepo-broker-service/rabbitmq.conf b/dbrepo-broker-service/rabbitmq.conf index ff592bb3ecd4b003d180dbb44d8bd9acc5a70394..8503942950feb8c701ac8765872d005249ee612b 100644 --- a/dbrepo-broker-service/rabbitmq.conf +++ b/dbrepo-broker-service/rabbitmq.conf @@ -6,7 +6,6 @@ default_user_tags.administrator = false listeners.tcp.1 = 0.0.0.0:5672 # management prefix (https://www.rabbitmq.com/management.html#path-prefix) -management.path_prefix = /admin/broker management.load_definitions = /app/definitions.json # logging @@ -14,6 +13,11 @@ log.console = true log.console.level = warning auth_ldap.log = true +# MQTT +mqtt.vhost = dbrepo +mqtt.exchange = dbrepo +mqtt.prefetch = 10 + # Obviously your authentication server cannot vouch for itself, so you'll need another backend with at least one user in # it. You should probably use the internal database auth_backends.1.authn = ldap diff --git a/dbrepo-dashboard-service/Dockerfile b/dbrepo-dashboard-service/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..00fc60339b15b2e1ebeda9dbbf7849c96bd7a401 --- /dev/null +++ b/dbrepo-dashboard-service/Dockerfile @@ -0,0 +1,9 @@ +FROM docker.io/bitnami/grafana:10.4.9-debian-12-r0 AS runtime +LABEL org.opencontainers.image.authors="martin.weise@tuwien.ac.at" + +WORKDIR /app + +COPY --chown=grafana:grafana ./dashboards /app/dashboards +COPY --chown=grafana:grafana ./provisioning /etc/grafana/provisioning +COPY --chown=grafana:grafana ./grafana.ini /etc/grafana/grafana.ini +COPY --chown=grafana:grafana ./ldap.toml /etc/grafana/ldap.toml diff --git a/dbrepo-dashboard-service/dashboards/rabbitmq.json b/dbrepo-dashboard-service/dashboards/rabbitmq.json new file mode 100644 index 0000000000000000000000000000000000000000..a8db65695f2dfef0484ebd91fcb7401f31f9f70d --- /dev/null +++ b/dbrepo-dashboard-service/dashboards/rabbitmq.json @@ -0,0 +1,8165 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "description": "A new RabbitMQ Management Overview", + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 1, + "id": null, + "iteration": 1659711638455, + "links": [ + { + "icon": "doc", + "tags": [], + "targetBlank": true, + "title": "Monitoring with Prometheus & Grafana", + "tooltip": "", + "type": "link", + "url": "https://www.rabbitmq.com/prometheus.html" + } + ], + "liveNow": false, + "panels": [ + { + "datasource": { + "default": true, + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#37872D", + "value": null + }, + { + "color": "#1F60C4", + "value": 10000 + }, + { + "color": "#C4162A", + "value": 100000 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "id": 64, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(rabbitmq_queue_messages_ready * on(instance, job) group_left(rabbitmq_cluster) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"})", + "format": "time_series", + "hide": false, + "instant": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "title": "Ready messages", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#C4162A", + "value": null + }, + { + "color": "#1F60C4", + "value": -1 + }, + { + "color": "#37872D", + "value": 50 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 6, + "y": 0 + }, + "id": 62, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(rate(rabbitmq_global_messages_received_total[60s]) * on(instance, job) group_left(rabbitmq_cluster) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"})", + "format": "time_series", + "instant": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "title": "Incoming messages / s", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#C4162A", + "value": null + }, + { + "color": "#1F60C4", + "value": 0 + }, + { + "color": "#37872D", + "value": 10 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 12, + "y": 0 + }, + "id": 66, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(rabbitmq_global_publishers * on(instance, job) group_left(rabbitmq_cluster) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"})", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "title": "Publishers", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#C4162A", + "value": null + }, + { + "color": "#1F60C4", + "value": 0 + }, + { + "color": "#37872D", + "value": 10 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 16, + "y": 0 + }, + "id": 37, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(rabbitmq_connections * on(instance, job) group_left(rabbitmq_cluster) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"})", + "format": "time_series", + "instant": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "title": "Connections", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#C4162A", + "value": null + }, + { + "color": "#1F60C4", + "value": 0 + }, + { + "color": "#37872D", + "value": 10 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 20, + "y": 0 + }, + "id": 40, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(rabbitmq_queues * on(instance, job) group_left(rabbitmq_cluster) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"})", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "title": "Queues", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#37872D", + "value": null + }, + { + "color": "#1F60C4", + "value": 100 + }, + { + "color": "#C4162A", + "value": 500 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 0, + "y": 3 + }, + "id": 65, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(rabbitmq_queue_messages_unacked * on(instance, job) group_left(rabbitmq_cluster) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"})", + "format": "time_series", + "hide": false, + "instant": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "title": "Unacknowledged messages", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#C4162A", + "value": null + }, + { + "color": "#1F60C4", + "value": -1 + }, + { + "color": "#37872D", + "value": 50 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 6, + "y": 3 + }, + "id": 63, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(rate(rabbitmq_global_messages_redelivered_total[60s]) * on(instance, job) group_left(rabbitmq_cluster) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}) +\nsum(rate(rabbitmq_global_messages_delivered_consume_auto_ack_total[60s]) * on(instance, job) group_left(rabbitmq_cluster) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}) +\nsum(rate(rabbitmq_global_messages_delivered_consume_manual_ack_total[60s]) * on(instance, job) group_left(rabbitmq_cluster) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}) +\nsum(rate(rabbitmq_global_messages_delivered_get_auto_ack_total[60s]) * on(instance, job) group_left(rabbitmq_cluster) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}) +\nsum(rate(rabbitmq_global_messages_delivered_get_manual_ack_total[60s]) * on(instance, job) group_left(rabbitmq_cluster) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"})", + "format": "time_series", + "hide": false, + "instant": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "title": "Outgoing messages / s", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#C4162A", + "value": null + }, + { + "color": "#1F60C4", + "value": 0 + }, + { + "color": "#37872D", + "value": 10 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 12, + "y": 3 + }, + "id": 41, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(rabbitmq_consumers * on(instance, job) group_left(rabbitmq_cluster) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"})", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "title": "Consumers", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#C4162A", + "value": null + }, + { + "color": "#1F60C4", + "value": 0 + }, + { + "color": "#37872D", + "value": 10 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 16, + "y": 3 + }, + "id": 38, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(rabbitmq_channels * on(instance, job) group_left(rabbitmq_cluster) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"})", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "title": "Channels", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#1F60C4", + "value": null + }, + { + "color": "#37872D", + "value": 3 + }, + { + "color": "#C4162A", + "value": 8 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 20, + "y": 3 + }, + "id": 67, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(rabbitmq_build_info * on(instance, job) group_left(rabbitmq_cluster) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"})", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "title": "Nodes", + "type": "stat" + }, + { + "collapsed": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 6 + }, + "id": 4, + "panels": [], + "title": "NODES", + "type": "row" + }, + { + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "displayMode": "auto" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "erlang_version" + }, + "properties": [ + { + "id": "displayName", + "value": "Erlang/OTP" + }, + { + "id": "unit", + "value": "none" + }, + { + "id": "custom.align" + }, + { + "id": "thresholds", + "value": { + "mode": "absolute", + "steps": [ + { + "color": "rgba(50, 172, 45, 0.97)", + "value": null + }, + { + "color": "rgba(237, 129, 40, 0.89)" + } + ] + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "rabbitmq_version" + }, + "properties": [ + { + "id": "displayName", + "value": "RabbitMQ" + }, + { + "id": "unit", + "value": "none" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + }, + { + "id": "thresholds", + "value": { + "mode": "absolute", + "steps": [ + { + "color": "rgba(245, 54, 54, 0.9)", + "value": null + }, + { + "color": "rgba(237, 129, 40, 0.89)" + } + ] + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "instance" + }, + "properties": [ + { + "id": "displayName", + "value": "Host" + }, + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "rabbitmq_node" + }, + "properties": [ + { + "id": "displayName", + "value": "Node name" + }, + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + }, + { + "id": "thresholds", + "value": { + "mode": "absolute", + "steps": [ + { + "color": "rgba(245, 54, 54, 0.9)", + "value": null + }, + { + "color": "rgba(237, 129, 40, 0.89)" + } + ] + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Time" + }, + "properties": [ + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Value" + }, + "properties": [ + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "job" + }, + "properties": [ + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "rabbitmq_cluster" + }, + "properties": [ + { + "id": "displayName", + "value": "Cluster" + }, + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "prometheus_client_version" + }, + "properties": [ + { + "id": "displayName", + "value": "prometheus.erl" + }, + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "prometheus_plugin_version" + }, + "properties": [ + { + "id": "displayName", + "value": "rabbitmq_prometheus" + }, + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 24, + "x": 0, + "y": 7 + }, + "id": 69, + "links": [], + "options": { + "footer": { + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "exemplar": false, + "expr": "rabbitmq_build_info * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}", + "format": "table", + "instant": true, + "interval": "", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "transformations": [ + { + "id": "merge", + "options": { + "reducers": [] + } + } + ], + "type": "table" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "If the value is zero or less, the memory alarm will be triggered and all publishing connections across all cluster nodes will be blocked.\n\nThis value can temporarily go negative because the memory alarm is triggered with a slight delay.\n\nThe kernel's view of the amount of memory used by the node can differ from what the node itself can observe. This means that this value can be negative for a sustained period of time.\n\nBy default nodes use resident set size (RSS) to compute how much memory they use. This strategy can be changed (see the guides below).\n\n* [Alarms](https://www.rabbitmq.com/alarms.html)\n* [Memory Alarms](https://www.rabbitmq.com/memory.html)\n* [Reasoning About Memory Use](https://www.rabbitmq.com/memory-use.html)\n* [Blocked Connection Notifications](https://www.rabbitmq.com/connection-blocked.html)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "line+area" + } + }, + "decimals": 1, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "orange", + "value": 0 + }, + { + "color": "transparent", + "value": 536870912 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?0(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#56A64B", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?1(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2CC0C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?2(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#3274D9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?3(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#A352CC", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?4(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FF780A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?5(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#96D98D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?6(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFEE52", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?7(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#8AB8FF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?8(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CA95E5", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?9(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFB357", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 11 + }, + "id": 7, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "(rabbitmq_resident_memory_limit_bytes * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}) -\n(rabbitmq_process_resident_memory_bytes * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"})", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "{{rabbitmq_node}}", + "refId": "A" + } + ], + "title": "Memory available before publishers blocked", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "This metric is reported for the partition where the RabbitMQ data directory is stored.\n\nIf the value is zero or less, the disk alarm will be triggered and all publishing connections across all cluster nodes will be blocked.\n\nThis value can temporarily go negative because the free disk space alarm is triggered with a slight delay.\n\n* [Alarms](https://www.rabbitmq.com/alarms.html)\n* [Disk Space Alarms](https://www.rabbitmq.com/disk-alarms.html)\n* [Disk Space](https://www.rabbitmq.com/production-checklist.html#resource-limits-disk-space)\n* [Persistence Configuration](https://www.rabbitmq.com/persistence-conf.html)\n* [Blocked Connection Notifications](https://www.rabbitmq.com/connection-blocked.html)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "line+area" + } + }, + "decimals": 1, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "orange", + "value": 1073741824 + }, + { + "color": "transparent", + "value": 5368709120 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?0(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#56A64B", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?1(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2CC0C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?2(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#3274D9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?3(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#A352CC", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?4(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FF780A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?5(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#96D98D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?6(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFEE52", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?7(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#8AB8FF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?8(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CA95E5", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?9(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFB357", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 12, + "y": 11 + }, + "id": 8, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "rabbitmq_disk_space_available_bytes * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "{{rabbitmq_node}}", + "refId": "A" + } + ], + "title": "Disk space available before publishers blocked", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "When this value reaches zero, new connections will not be accepted and disk write operations may fail.\n\nClient libraries, peer nodes and CLI tools will not be able to connect when the node runs out of available file descriptors.\n\n* [Open File Handles Limit](https://www.rabbitmq.com/production-checklist.html#resource-limits-file-handle-limit)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "line+area" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "orange", + "value": 500 + }, + { + "color": "transparent", + "value": 1000 + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?0(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#56A64B", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?1(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2CC0C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?2(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#3274D9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?3(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#A352CC", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?4(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FF780A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?5(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#96D98D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?6(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFEE52", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?7(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#8AB8FF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?8(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CA95E5", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?9(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFB357", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 20, + "y": 11 + }, + "id": 2, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "(rabbitmq_process_max_fds * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}) -\n(rabbitmq_process_open_fds * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"})", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "{{rabbitmq_node}}", + "refId": "A" + } + ], + "title": "File descriptors available", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "When this value reaches zero, new connections will not be accepted.\n\nClient libraries, peer nodes and CLI tools will not be able to connect when the node runs out of available file descriptors.\n\n* [Networking and RabbitMQ](https://www.rabbitmq.com/networking.html)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "line+area" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "orange", + "value": 500 + }, + { + "color": "transparent", + "value": 1000 + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?0(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#56A64B", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?1(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2CC0C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?2(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#3274D9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?3(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#A352CC", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?4(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FF780A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?5(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#96D98D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?6(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFEE52", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?7(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#8AB8FF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?8(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CA95E5", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?9(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFB357", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 20, + "y": 15 + }, + "id": 5, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "(rabbitmq_process_max_tcp_sockets * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}) -\n(rabbitmq_process_open_tcp_sockets * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"})", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "{{rabbitmq_node}}", + "refId": "A" + } + ], + "title": "TCP sockets available", + "type": "timeseries" + }, + { + "collapsed": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 19 + }, + "id": 27, + "panels": [], + "title": "QUEUED MESSAGES", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "Total number of ready messages ready to be delivered to consumers.\n\nAim to keep this value as low as possible. RabbitMQ behaves best when messages are flowing through it. It's OK for publishers to occasionally outpace consumers, but the expectation is that consumers will eventually process all ready messages.\n\nIf this metric keeps increasing, your system will eventually run out of memory and/or disk space. Consider using TTL or Queue Length Limit to prevent unbounded message growth.\n\n* [Queues](https://www.rabbitmq.com/queues.html)\n* [Consumers](https://www.rabbitmq.com/consumers.html)\n* [Queue Length Limit](https://www.rabbitmq.com/maxlength.html)\n* [Time-To-Live and Expiration](https://www.rabbitmq.com/ttl.html)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 0, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?0(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#56A64B", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?1(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2CC0C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?2(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#3274D9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?3(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#A352CC", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?4(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FF780A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?5(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#96D98D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?6(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFEE52", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?7(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#8AB8FF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?8(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CA95E5", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?9(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFB357", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 12, + "x": 0, + "y": 20 + }, + "id": 9, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(rabbitmq_queue_messages_ready * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}) by(rabbitmq_node)", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "{{rabbitmq_node}}", + "refId": "A" + } + ], + "title": "Messages ready to be delivered to consumers", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "The total number of messages that are either in-flight to consumers, currently being processed by consumers or simply waiting for the consumer acknowledgements to be processed by the queue. Until the queue processes the message acknowledgement, the message will remain unacknowledged.\n\n* [Queues](https://www.rabbitmq.com/queues.html)\n* [Confirms and Acknowledgements](https://www.rabbitmq.com/confirms.html)\n* [Consumer Prefetch](https://www.rabbitmq.com/consumer-prefetch.html)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 0, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?0(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#56A64B", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?1(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2CC0C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?2(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#3274D9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?3(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#A352CC", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?4(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FF780A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?5(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#96D98D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?6(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFEE52", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?7(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#8AB8FF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?8(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CA95E5", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?9(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFB357", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 12, + "x": 12, + "y": 20 + }, + "id": 19, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(rabbitmq_queue_messages_unacked * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}) by(rabbitmq_node)", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "{{rabbitmq_node}}", + "refId": "A" + } + ], + "title": "Messages pending consumer acknowledgement", + "type": "timeseries" + }, + { + "collapsed": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 25 + }, + "id": 11, + "panels": [], + "title": "INCOMING MESSAGES", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "The incoming message rate before any routing rules are applied.\n\nIf this value is lower than the number of messages published to queues, it may indicate that some messages are delivered to more than one queue.\n\nIf this value is higher than the number of messages published to queues, messages cannot be routed and will either be dropped or returned to publishers.\n\n* [Publishers](https://www.rabbitmq.com/publishers.html)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 0, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?0(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#56A64B", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?1(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2CC0C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?2(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#3274D9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?3(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#A352CC", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?4(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FF780A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?5(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#96D98D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?6(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFEE52", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?7(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#8AB8FF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?8(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CA95E5", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?9(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFB357", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 12, + "x": 0, + "y": 26 + }, + "id": 13, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(rate(rabbitmq_global_messages_received_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}) by(rabbitmq_node)", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "{{rabbitmq_node}}", + "refId": "A" + } + ], + "title": "Messages published / s", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "The rate of messages confirmed by the broker to publishers. Publishers must opt-in to receive message confirmations.\n\nIf this metric is consistently at zero it may suggest that publisher confirms are not used by clients. The safety of published messages is likely to be at risk.\n\n* [Publisher Confirms](https://www.rabbitmq.com/confirms.html#publisher-confirms)\n* [Publisher Confirms and Data Safety](https://www.rabbitmq.com/publishers.html#data-safety)\n* [When Will Published Messages Be Confirmed by the Broker?](https://www.rabbitmq.com/confirms.html#when-publishes-are-confirmed)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 0, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?0(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#56A64B", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?1(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2CC0C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?2(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#3274D9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?3(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#A352CC", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?4(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FF780A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?5(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#96D98D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?6(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFEE52", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?7(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#8AB8FF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?8(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CA95E5", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?9(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFB357", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 12, + "x": 12, + "y": 26 + }, + "id": 18, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(rate(rabbitmq_global_messages_confirmed_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}) by(rabbitmq_node)", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "{{rabbitmq_node}}", + "refId": "A" + } + ], + "title": "Messages confirmed to publishers / s", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "The rate of messages received from publishers and successfully routed to the master queue replicas.\n\n* [Queues](https://www.rabbitmq.com/queues.html)\n* [Publishers](https://www.rabbitmq.com/publishers.html)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 0, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?0(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#56A64B", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?1(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2CC0C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?2(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#3274D9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?3(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#A352CC", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?4(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FF780A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?5(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#96D98D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?6(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFEE52", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?7(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#8AB8FF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?8(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CA95E5", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?9(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFB357", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 12, + "x": 0, + "y": 31 + }, + "id": 61, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(rate(rabbitmq_global_messages_routed_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}) by(rabbitmq_node)", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "{{rabbitmq_node}}", + "refId": "A" + } + ], + "title": "Messages routed to queues / s", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "The rate of messages received from publishers that have publisher confirms enabled and the broker has not confirmed yet.\n\n* [Publishers](https://www.rabbitmq.com/publishers.html)\n* [Confirms and Acknowledgements](https://www.rabbitmq.com/confirms.html)\n* [When Will Published Messages Be Confirmed by the Broker?](https://www.rabbitmq.com/confirms.html#when-publishes-are-confirmed)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 0, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?0(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#56A64B", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?1(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2CC0C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?2(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#3274D9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?3(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#A352CC", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?4(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FF780A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?5(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#96D98D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?6(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFEE52", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?7(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#8AB8FF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?8(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CA95E5", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?9(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFB357", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 12, + "x": 12, + "y": 31 + }, + "id": 12, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(rate(rabbitmq_global_messages_received_confirm_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"} - \nrate(rabbitmq_global_messages_confirmed_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}\n) by(rabbitmq_node)", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "{{rabbitmq_node}}", + "refId": "A" + } + ], + "title": "Messages unconfirmed to publishers / s", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "The rate of messages that cannot be routed and are dropped. \n\nAny value above zero means message loss and likely suggests a routing problem on the publisher end.\n\n* [Unroutable Message Handling](https://www.rabbitmq.com/publishers.html#unroutable)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "line+area" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "transparent", + "value": null + }, + { + "color": "red", + "value": 0 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/rabbit/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C4162A", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 12, + "x": 0, + "y": 36 + }, + "id": 34, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(rate(rabbitmq_global_messages_unroutable_dropped_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}) by(rabbitmq_node)", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "{{rabbitmq_node}}", + "refId": "A" + } + ], + "title": "Unroutable messages dropped / s", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "The rate of messages that cannot be routed and are returned back to publishers.\n\nSustained values above zero may indicate a routing problem on the publisher end.\n\n* [Unroutable Message Handling](https://www.rabbitmq.com/publishers.html#unroutable)\n* [When Will Published Messages Be Confirmed by the Broker?](https://www.rabbitmq.com/confirms.html#when-publishes-are-confirmed)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "line+area" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "transparent", + "value": null + }, + { + "color": "red", + "value": 0 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/rabbit/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C4162A", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 12, + "x": 12, + "y": 36 + }, + "id": 16, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(rate(rabbitmq_global_messages_unroutable_returned_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}) by(rabbitmq_node)", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "{{rabbitmq_node}}", + "refId": "A" + } + ], + "title": "Unroutable messages returned to publishers / s", + "type": "timeseries" + }, + { + "collapsed": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 41 + }, + "id": 29, + "panels": [], + "title": "OUTGOING MESSAGES", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "The rate of messages delivered to consumers. It includes messages that have been redelivered.\n\nThis metric does not include messages that have been fetched by consumers using `basic.get` (consumed by polling).\n\n* [Consumers](https://www.rabbitmq.com/consumers.html)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 0, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?0(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#56A64B", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?1(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2CC0C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?2(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#3274D9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?3(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#A352CC", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?4(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FF780A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?5(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#96D98D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?6(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFEE52", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?7(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#8AB8FF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?8(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CA95E5", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?9(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFB357", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 12, + "x": 0, + "y": 42 + }, + "id": 14, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(\n (rate(rabbitmq_global_messages_delivered_consume_auto_ack_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}) +\n (rate(rabbitmq_global_messages_delivered_consume_manual_ack_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"})\n) by(rabbitmq_node)", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "{{rabbitmq_node}}", + "refId": "A" + } + ], + "title": "Messages delivered / s", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "The rate of messages that have been redelivered to consumers. It includes messages that have been requeued automatically and redelivered due to channel exceptions or connection closures.\n\nHaving some redeliveries is expected, but if this metric is consistently non-zero, it is worth investigating why.\n\n* [Negative Acknowledgement and Requeuing of Deliveries](https://www.rabbitmq.com/confirms.html#consumer-nacks-requeue)\n* [Consumers](https://www.rabbitmq.com/consumers.html)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "line+area" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "transparent", + "value": null + }, + { + "color": "orange", + "value": 20 + }, + { + "color": "red", + "value": 100 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?0(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#56A64B", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?1(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2CC0C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?2(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#3274D9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?3(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#A352CC", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?4(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FF780A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?5(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#96D98D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?6(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFEE52", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?7(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#8AB8FF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?8(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CA95E5", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?9(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFB357", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 12, + "x": 12, + "y": 42 + }, + "id": 15, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(rate(rabbitmq_global_messages_redelivered_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}) by(rabbitmq_node)", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "{{rabbitmq_node}}", + "refId": "A" + } + ], + "title": "Messages redelivered / s", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "The rate of message deliveries to consumers that use manual acknowledgement mode.\n\nWhen this mode is used, RabbitMQ waits for consumers to acknowledge messages before more messages can be delivered.\n\nThis is the safest way of consuming messages.\n\n* [Consumer Acknowledgements](https://www.rabbitmq.com/confirms.html)\n* [Consumer Prefetch](https://www.rabbitmq.com/consumer-prefetch.html)\n* [Consumer Acknowledgement Modes, Prefetch and Throughput](https://www.rabbitmq.com/confirms.html#channel-qos-prefetch-throughput)\n* [Consumers](https://www.rabbitmq.com/consumers.html)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 0, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?0(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#56A64B", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?1(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2CC0C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?2(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#3274D9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?3(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#A352CC", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?4(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FF780A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?5(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#96D98D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?6(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFEE52", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?7(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#8AB8FF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?8(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CA95E5", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?9(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFB357", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 12, + "x": 0, + "y": 47 + }, + "id": 20, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(rate(rabbitmq_global_messages_delivered_consume_manual_ack_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}) by(rabbitmq_node)", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "{{rabbitmq_node}}", + "refId": "A" + } + ], + "title": "Messages delivered with manual ack / s", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "The rate of message deliveries to consumers that use automatic acknowledgement mode.\n\nWhen this mode is used, RabbitMQ does not wait for consumers to acknowledge message deliveries.\n\nThis mode is fire-and-forget and does not offer any delivery safety guarantees. It tends to provide higher throughput and it may lead to consumer overload and higher consumer memory usage.\n\n* [Consumer Acknowledgement Modes, Prefetch and Throughput](https://www.rabbitmq.com/confirms.html#channel-qos-prefetch-throughput)\n* [Consumers](https://www.rabbitmq.com/consumers.html)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 0, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?0(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#56A64B", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?1(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2CC0C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?2(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#3274D9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?3(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#A352CC", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?4(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FF780A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?5(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#96D98D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?6(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFEE52", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?7(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#8AB8FF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?8(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CA95E5", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?9(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFB357", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 12, + "x": 12, + "y": 47 + }, + "id": 21, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(rate(rabbitmq_global_messages_delivered_consume_auto_ack_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}) by(rabbitmq_node)", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "{{rabbitmq_node}}", + "refId": "A" + } + ], + "title": "Messages delivered auto ack / s", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "The rate of message acknowledgements coming from consumers that use manual acknowledgement mode.\n\n* [Consumer Acknowledgements](https://www.rabbitmq.com/confirms.html)\n* [Consumer Prefetch](https://www.rabbitmq.com/consumer-prefetch.html)\n* [Consumer Acknowledgement Modes, Prefetch and Throughput](https://www.rabbitmq.com/confirms.html#channel-qos-prefetch-throughput)\n* [Consumers](https://www.rabbitmq.com/consumers.html)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 0, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?0(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#56A64B", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?1(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2CC0C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?2(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#3274D9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?3(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#A352CC", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?4(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FF780A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?5(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#96D98D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?6(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFEE52", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?7(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#8AB8FF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?8(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CA95E5", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?9(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFB357", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 12, + "x": 0, + "y": 52 + }, + "id": 22, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(rate(rabbitmq_global_messages_acknowledged_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}) by(rabbitmq_node)", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "{{rabbitmq_node}}", + "refId": "A" + } + ], + "title": "Messages acknowledged / s", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "The rate of messages delivered to polling consumers that use automatic acknowledgement mode.\n\nThe use of polling consumers is highly inefficient and therefore strongly discouraged.\n\n* [Fetching individual messages](https://www.rabbitmq.com/consumers.html#fetching)\n* [Consumers](https://www.rabbitmq.com/consumers.html)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "line+area" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "transparent", + "value": null + }, + { + "color": "red", + "value": 0 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/rabbit/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C4162A", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 12, + "x": 12, + "y": 52 + }, + "id": 24, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(rate(rabbitmq_global_messages_delivered_get_auto_ack_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}) by(rabbitmq_node)", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "{{rabbitmq_node}}", + "refId": "A" + } + ], + "title": "Polling operations with auto ack / s", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "The rate of polling consumer operations that yield no result.\n\nAny value above zero means that RabbitMQ resources are wasted by polling consumers.\n\nCompare this metric to the other polling consumer metrics to see the inefficiency rate.\n\nThe use of polling consumers is highly inefficient and therefore strongly discouraged.\n\n* [Fetching individual messages](https://www.rabbitmq.com/consumers.html#fetching)\n* [Consumers](https://www.rabbitmq.com/consumers.html)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "line+area" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "transparent", + "value": null + }, + { + "color": "red", + "value": 0 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/rabbit/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C4162A", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 12, + "x": 0, + "y": 57 + }, + "id": 25, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(rate(rabbitmq_global_messages_get_empty_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}) by(rabbitmq_node)", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "{{rabbitmq_node}}", + "refId": "A" + } + ], + "title": "Polling operations that yield no result / s", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "The rate of messages delivered to polling consumers that use manual acknowledgement mode.\n\nThe use of polling consumers is highly inefficient and therefore strongly discouraged.\n\n* [Fetching individual messages](https://www.rabbitmq.com/consumers.html#fetching)\n* [Consumers](https://www.rabbitmq.com/consumers.html)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "line+area" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "transparent", + "value": null + }, + { + "color": "red", + "value": 0 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/rabbit/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C4162A", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 12, + "x": 12, + "y": 57 + }, + "id": 23, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(rate(rabbitmq_global_messages_delivered_get_manual_ack_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}) by(rabbitmq_node)", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "{{rabbitmq_node}}", + "refId": "A" + } + ], + "title": "Polling operations with manual ack / s", + "type": "timeseries" + }, + { + "collapsed": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 62 + }, + "id": 53, + "panels": [], + "title": "QUEUES", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "Total number of queue masters per node. \n\nThis metric makes it easy to see sub-optimal queue distribution in a cluster.\n\n* [Queue Masters, Data Locality](https://www.rabbitmq.com/ha.html#master-migration-data-locality)\n* [Queues](https://www.rabbitmq.com/queues.html)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?0(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#56A64B", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?1(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2CC0C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?2(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#3274D9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?3(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#A352CC", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?4(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FF780A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?5(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#96D98D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?6(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFEE52", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?7(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#8AB8FF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?8(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CA95E5", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?9(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFB357", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 12, + "x": 0, + "y": 63 + }, + "id": 57, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "rabbitmq_queues * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}", + "format": "time_series", + "instant": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{rabbitmq_node}}", + "refId": "A" + } + ], + "title": "Total queues", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "The rate of queue declarations performed by clients.\n\nLow sustained values above zero are to be expected. High rates may be indicative of queue churn or high rates of connection recovery. Confirm connection recovery rates by using the _Connections opened_ metric.\n\n* [Queues](https://www.rabbitmq.com/queues.html)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "line+area" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "transparent", + "value": null + }, + { + "color": "orange", + "value": 2 + }, + { + "color": "red", + "value": 10 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?0(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#56A64B", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?1(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2CC0C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?2(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#3274D9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?3(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#A352CC", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?4(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FF780A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?5(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#96D98D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?6(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFEE52", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?7(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#8AB8FF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?8(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CA95E5", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?9(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFB357", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 4, + "x": 12, + "y": 63 + }, + "id": 58, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(rate(rabbitmq_queues_declared_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}) by(rabbitmq_node)", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "{{rabbitmq_node}}", + "refId": "A" + } + ], + "title": "Queues declared / s", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "The rate of new queues created (as opposed to redeclarations).\n\nLow sustained values above zero are to be expected. High rates may be indicative of queue churn or high rates of connection recovery. Confirm connection recovery rates by using the _Connections opened_ metric.\n\n* [Queues](https://www.rabbitmq.com/queues.html)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "line+area" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "transparent", + "value": null + }, + { + "color": "orange", + "value": 2 + }, + { + "color": "red", + "value": 10 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?0(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#56A64B", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?1(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2CC0C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?2(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#3274D9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?3(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#A352CC", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?4(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FF780A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?5(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#96D98D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?6(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFEE52", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?7(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#8AB8FF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?8(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CA95E5", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?9(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFB357", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 4, + "x": 16, + "y": 63 + }, + "id": 60, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(rate(rabbitmq_queues_created_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}) by(rabbitmq_node)", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "{{rabbitmq_node}}", + "refId": "A" + } + ], + "title": "Queues created / s", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "The rate of queues deleted.\n\nLow sustained values above zero are to be expected. High rates may be indicative of queue churn or high rates of connection recovery. Confirm connection recovery rates by using the _Connections opened_ metric.\n\n* [Queues](https://www.rabbitmq.com/queues.html)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "line+area" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "transparent", + "value": null + }, + { + "color": "orange", + "value": 2 + }, + { + "color": "red", + "value": 10 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?0(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#56A64B", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?1(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2CC0C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?2(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#3274D9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?3(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#A352CC", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?4(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FF780A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?5(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#96D98D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?6(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFEE52", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?7(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#8AB8FF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?8(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CA95E5", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?9(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFB357", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 4, + "x": 20, + "y": 63 + }, + "id": 59, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(rate(rabbitmq_queues_deleted_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}) by(rabbitmq_node)", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "{{rabbitmq_node}}", + "refId": "A" + } + ], + "title": "Queues deleted / s", + "type": "timeseries" + }, + { + "collapsed": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 68 + }, + "id": 51, + "panels": [], + "title": "CHANNELS", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "Total number of channels on all currently opened connections.\n\nIf this metric grows monotonically it is highly likely a channel leak in one of the applications. Confirm channel leaks by using the _Channels opened_ and _Channels closed_ metrics.\n\n* [Channel Leak](https://www.rabbitmq.com/channels.html#channel-leaks)\n* [Channels](https://www.rabbitmq.com/channels.html)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?0(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#56A64B", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?1(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2CC0C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?2(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#3274D9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?3(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#A352CC", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?4(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FF780A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?5(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#96D98D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?6(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFEE52", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?7(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#8AB8FF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?8(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CA95E5", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?9(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFB357", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 12, + "x": 0, + "y": 69 + }, + "id": 54, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "rabbitmq_channels * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "{{rabbitmq_node}}", + "refId": "A" + } + ], + "title": "Total channels", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "The rate of new channels opened by applications across all connections. Channels are expected to be long-lived.\n\nLow sustained values above zero are to be expected. High rates may be indicative of channel churn or mass connection recovery. Confirm connection recovery rates by using the _Connections opened_ metric.\n\n* [High Channel Churn](https://www.rabbitmq.com/channels.html#high-channel-churn)\n* [Channels](https://www.rabbitmq.com/channels.html)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "line+area" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "transparent", + "value": null + }, + { + "color": "orange", + "value": 2 + }, + { + "color": "red", + "value": 10 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?0(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#56A64B", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?1(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2CC0C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?2(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#3274D9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?3(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#A352CC", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?4(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FF780A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?5(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#96D98D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?6(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFEE52", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?7(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#8AB8FF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?8(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CA95E5", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?9(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFB357", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 6, + "x": 12, + "y": 69 + }, + "id": 55, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(rate(rabbitmq_channels_opened_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}) by(rabbitmq_node)", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "{{rabbitmq_node}}", + "refId": "A" + } + ], + "title": "Channels opened / s", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "The rate of channels closed by applications across all connections. Channels are expected to be long-lived.\n\nLow sustained values above zero are to be expected. High rates may be indicative of channel churn or mass connection recovery. Confirm connection recovery rates by using the _Connections opened_ metric.\n\n* [High Channel Churn](https://www.rabbitmq.com/channels.html#high-channel-churn)\n* [Channels](https://www.rabbitmq.com/channels.html)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "line+area" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "transparent", + "value": null + }, + { + "color": "orange", + "value": 2 + }, + { + "color": "red", + "value": 10 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?0(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#56A64B", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?1(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2CC0C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?2(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#3274D9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?3(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#A352CC", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?4(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FF780A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?5(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#96D98D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?6(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFEE52", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?7(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#8AB8FF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?8(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CA95E5", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?9(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFB357", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 6, + "x": 18, + "y": 69 + }, + "id": 56, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(rate(rabbitmq_channels_closed_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}) by(rabbitmq_node)", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "{{rabbitmq_node}}", + "refId": "A" + } + ], + "title": "Channels closed / s", + "type": "timeseries" + }, + { + "collapsed": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 74 + }, + "id": 46, + "panels": [], + "title": "CONNECTIONS", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "Total number of client connections.\n\nIf this metric grows monotonically it is highly likely a connection leak in one of the applications. Confirm connection leaks by using the _Connections opened_ and _Connections closed_ metrics.\n\n* [Connection Leak](https://www.rabbitmq.com/connections.html#monitoring)\n* [Connections](https://www.rabbitmq.com/connections.html)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?0(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#56A64B", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?1(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2CC0C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?2(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#3274D9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?3(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#A352CC", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?4(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FF780A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?5(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#96D98D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?6(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFEE52", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?7(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#8AB8FF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?8(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CA95E5", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?9(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFB357", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 12, + "x": 0, + "y": 75 + }, + "id": 47, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "rabbitmq_connections * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "{{rabbitmq_node}}", + "refId": "A" + } + ], + "title": "Total connections", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "The rate of new connections opened by clients. Connections are expected to be long-lived.\n\nLow sustained values above zero are to be expected. High rates may be indicative of connection churn or mass connection recovery.\n\n* [Connection Leak](https://www.rabbitmq.com/connections.html#monitoring)\n* [Connections](https://www.rabbitmq.com/connections.html)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "line+area" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "transparent", + "value": null + }, + { + "color": "orange", + "value": 2 + }, + { + "color": "red", + "value": 10 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?0(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#56A64B", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?1(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2CC0C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?2(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#3274D9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?3(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#A352CC", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?4(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FF780A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?5(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#96D98D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?6(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFEE52", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?7(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#8AB8FF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?8(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CA95E5", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?9(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFB357", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 6, + "x": 12, + "y": 75 + }, + "id": 48, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(rate(rabbitmq_connections_opened_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}) by(rabbitmq_node)", + "format": "time_series", + "instant": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{rabbitmq_node}}", + "refId": "A" + } + ], + "title": "Connections opened / s", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "The rate of connections closed. Connections are expected to be long-lived.\n\nLow sustained values above zero are to be expected. High rates may be indicative of connection churn or mass connection recovery.\n\n* [Connections](https://www.rabbitmq.com/connections.html)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "line+area" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "transparent", + "value": null + }, + { + "color": "orange", + "value": 2 + }, + { + "color": "red", + "value": 10 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?0(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#56A64B", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?1(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2CC0C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?2(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#3274D9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?3(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#A352CC", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?4(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FF780A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?5(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#96D98D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?6(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFEE52", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?7(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#8AB8FF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?8(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CA95E5", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?9(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFB357", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 6, + "x": 18, + "y": 75 + }, + "id": 49, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(rate(rabbitmq_connections_closed_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}) by(rabbitmq_node)", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "{{rabbitmq_node}}", + "refId": "A" + } + ], + "title": "Connections closed / s", + "type": "timeseries" + } + ], + "refresh": "15s", + "schemaVersion": 34, + "style": "dark", + "tags": ["provisioned", "rabbitmq"], + "templating": { + "list": [ + { + "current": { + "selected": false, + "text": "default", + "value": "default" + }, + "datasource": "PBFA97CFB590B2093", + "hide": 2, + "includeAll": false, + "label": "datasource", + "multi": false, + "name": "DS_PROMETHEUS", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "definition": "label_values(rabbitmq_identity_info, namespace)", + "hide": 0, + "includeAll": false, + "label": "Namespace", + "multi": false, + "name": "namespace", + "options": [], + "query": { + "query": "label_values(rabbitmq_identity_info, namespace)", + "refId": "Prometheus-namespace-Variable-Query" + }, + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "definition": "label_values(rabbitmq_identity_info{namespace=\"$namespace\"}, rabbitmq_cluster)", + "hide": 0, + "includeAll": false, + "label": "RabbitMQ Cluster", + "multi": false, + "name": "rabbitmq_cluster", + "options": [], + "query": { + "query": "label_values(rabbitmq_identity_info{namespace=\"$namespace\"}, rabbitmq_cluster)", + "refId": "Prometheus-rabbitmq_cluster-Variable-Query" + }, + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-15m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "15s", + "30s", + "1m", + "5m", + "10m" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "RabbitMQ - Overview", + "uid": "Kn5xm-gZk", + "version": 20220805, + "weekStart": "", + "gnetId": 10991 +} \ No newline at end of file diff --git a/dbrepo-dashboard-service/dashboards/system.json b/dbrepo-dashboard-service/dashboards/system.json new file mode 100644 index 0000000000000000000000000000000000000000..d0234fe47706400ed5e75b72906b8a61461a09bf --- /dev/null +++ b/dbrepo-dashboard-service/dashboards/system.json @@ -0,0 +1,2183 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 1, + "links": [ + { + "asDropdown": false, + "icon": "external link", + "includeVars": false, + "keepTime": false, + "tags": [], + "targetBlank": false, + "title": "Docs", + "tooltip": "", + "type": "link", + "url": "https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.4.6/" + } + ], + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 15, + "panels": [], + "title": "Data", + "type": "row" + }, + { + "datasource": { + "default": true, + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 0, + "y": 1 + }, + "id": 4, + "options": { + "colorMode": "background", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "10.4.9", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "dbrepo_database_count", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Databases", + "type": "stat" + }, + { + "datasource": { + "default": true, + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 4, + "y": 1 + }, + "id": 5, + "options": { + "colorMode": "background", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "10.4.9", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "dbrepo_view_count", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "Views", + "useBackend": false + }, + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "dbrepo_subset_count", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "Subsets", + "useBackend": false + }, + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "dbrepo_table_count", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "Tables", + "useBackend": false + } + ], + "title": "Datasources", + "transformations": [ + { + "id": "calculateField", + "options": { + "alias": "", + "mode": "reduceRow", + "reduce": { + "reducer": "sum" + }, + "replaceFields": true + } + } + ], + "type": "stat" + }, + { + "datasource": { + "default": true, + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "description": "", + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "decbytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 8, + "y": 1 + }, + "id": 8, + "options": { + "colorMode": "background", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "10.4.9", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "dbrepo_volume_sum", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Data Volume", + "type": "stat" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 4 + }, + "id": 22, + "panels": [], + "title": "UI", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "description": "", + "fieldConfig": { + "defaults": { + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "#EAB839", + "value": 300 + }, + { + "color": "orange", + "value": 600 + }, + { + "color": "red", + "value": 900 + } + ] + }, + "unit": "ms" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 0, + "y": 5 + }, + "id": 17, + "options": { + "colorMode": "background", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "10.4.9", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "disableTextWrap": false, + "editorMode": "code", + "expr": "avg(page_render_time)", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "UI Response Time (avg)", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "description": "", + "fieldConfig": { + "defaults": { + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "#EAB839", + "value": 0.02 + }, + { + "color": "orange", + "value": 0.05 + }, + { + "color": "red", + "value": 0.1 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 4, + "y": 5 + }, + "id": 24, + "options": { + "colorMode": "background", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "10.4.9", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "disableTextWrap": false, + "editorMode": "code", + "expr": "nodejs_eventloop_lag_mean_seconds", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "UI Event Lag (avg)", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "description": "", + "fieldConfig": { + "defaults": { + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 8, + "y": 5 + }, + "id": 25, + "options": { + "colorMode": "background", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "10.4.9", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "disableTextWrap": false, + "editorMode": "code", + "expr": "nodejs_active_handles{type=\"Server\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "UI Servers", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "description": "", + "fieldConfig": { + "defaults": { + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 12, + "y": 5 + }, + "id": 26, + "options": { + "colorMode": "background", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "10.4.9", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "disableTextWrap": false, + "editorMode": "code", + "expr": "nodejs_active_handles{type=\"Socket\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "UI Sockets", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "blue", + "mode": "fixed" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 16, + "y": 5 + }, + "id": 27, + "options": { + "colorMode": "background", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "10.4.9", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "disableTextWrap": false, + "editorMode": "code", + "expr": "nodejs_active_requests_total", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Active Requests", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 300 + }, + { + "color": "orange", + "value": 600 + }, + { + "color": "red", + "value": 900 + } + ] + }, + "unit": "ms" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 8 + }, + "id": 20, + "options": { + "displayMode": "basic", + "maxVizHeight": 300, + "minVizHeight": 16, + "minVizWidth": 8, + "namePlacement": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showUnfilled": true, + "sizing": "auto", + "valueMode": "color" + }, + "pluginVersion": "10.4.9", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "page_render_time", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{{path}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "UI Response Time per Path (avg)", + "type": "bargauge" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "smooth", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "dashed" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 256000000 + } + ] + }, + "unit": "decbytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 8 + }, + "id": 21, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "nodejs_heap_space_size_total_bytes", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{{space}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "NodeJS Heap Bytes", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 15 + }, + "id": 2, + "panels": [], + "title": "Services", + "type": "row" + }, + { + "datasource": { + "default": true, + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "description": "Quality of Service", + "fieldConfig": { + "defaults": { + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "purple", + "value": null + }, + { + "color": "red", + "value": 0 + }, + { + "color": "orange", + "value": 60 + }, + { + "color": "#EAB839", + "value": 80 + }, + { + "color": "green", + "value": 100 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 0, + "y": 16 + }, + "id": 9, + "options": { + "colorMode": "background", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "10.4.9", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "disableTextWrap": false, + "editorMode": "code", + "expr": "sum(up)*100/count(up)", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "Services Running", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "QoS", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "description": "", + "fieldConfig": { + "defaults": { + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 4, + "y": 16 + }, + "id": 28, + "options": { + "colorMode": "background", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "10.4.9", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "disableTextWrap": false, + "editorMode": "code", + "expr": "min(process_uptime_seconds)", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Uptime", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "fillOpacity": 70, + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "mappings": [ + { + "options": { + "0": { + "index": 0, + "text": "DOWN" + }, + "1": { + "index": 1, + "text": "UP" + } + }, + "type": "value" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "green", + "value": 1 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 16 + }, + "id": 16, + "options": { + "colWidth": 0.9, + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "rowHeight": 0.9, + "showValue": "auto", + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "up", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{{instance}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Service QoS", + "type": "status-history" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "smooth", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 19 + }, + "id": 23, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "10.4.9", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "disableTextWrap": false, + "editorMode": "code", + "expr": "process_open_fds\n", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{{instance}}", + "range": true, + "refId": "process_open_fds", + "useBackend": false + } + ], + "title": "File Descriptors", + "type": "timeseries" + }, + { + "datasource": { + "default": true, + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "description": "Heap and non-heap memory summed", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 25, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "smooth", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "decbytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "auth-service:9000" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "data-service:8080" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "metadata-service:8080" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "metadata-service:80" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 23 + }, + "id": 7, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "11.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "sum by(instance) (jvm_memory_used_bytes)", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": false, + "instant": false, + "legendFormat": "{{instance}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "JVM Memory Usage", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 25, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "smooth", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "auth-service:9000" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "data-service:8080" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "metadata-service:8080" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "metadata-service:80" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 26 + }, + "id": 6, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "11.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "process_cpu_usage", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{{instance}}", + "range": true, + "refId": "process_cpu_usage", + "useBackend": false + } + ], + "title": "CPU Usage", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 25, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "smooth", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "reqps" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*search-service.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*analyse-service.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "super-light-orange", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 30 + }, + "id": 19, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "editorMode": "code", + "expr": "rate(flask_http_request_duration_seconds_count{status!~\"200|201|202\"}[$__rate_interval])", + "instant": false, + "legendFormat": "{{method}} {{instance}} ({{status}})", + "range": true, + "refId": "A" + } + ], + "title": "Failed API Requests", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 25, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "smooth", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "reqps" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*search-service.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*analyse-service.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "super-light-orange", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 33 + }, + "id": 18, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "editorMode": "code", + "expr": "rate(flask_http_request_duration_seconds_count{status=~\"200|201|202\",path!=\"/health\"}[$__rate_interval])", + "instant": false, + "legendFormat": "{{method}} {{instance}} {{path}} ({{status}})", + "range": true, + "refId": "A" + } + ], + "title": "Successful API Requests", + "type": "timeseries" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 40 + }, + "id": 31, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "description": "", + "fieldConfig": { + "defaults": { + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 0, + "y": 41 + }, + "id": 29, + "options": { + "colorMode": "background", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "10.4.9", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "disableTextWrap": false, + "editorMode": "code", + "expr": "nginx_connections_active", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Connections (Active)", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "description": "", + "fieldConfig": { + "defaults": { + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 1 + }, + { + "color": "orange", + "value": 3 + }, + { + "color": "red", + "value": 5 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 4, + "y": 41 + }, + "id": 30, + "options": { + "colorMode": "background", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "10.4.9", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "disableTextWrap": false, + "editorMode": "code", + "expr": "nginx_connections_waiting", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Connections (Waiting)", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "description": "", + "fieldConfig": { + "defaults": { + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 0.0001 + }, + { + "color": "orange", + "value": 0.001 + }, + { + "color": "red", + "value": 0.01 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 8, + "y": 41 + }, + "id": 33, + "options": { + "colorMode": "background", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "10.4.9", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "disableTextWrap": false, + "editorMode": "code", + "expr": "max(rate(promhttp_metric_handler_requests_total{job=\"gateway scrape\", code!=\"200\"}[24h]))", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Failed Requests (24h)", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "#EAB839", + "value": 0.0001 + }, + { + "color": "orange", + "value": 0.001 + }, + { + "color": "red", + "value": 0.01 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 41 + }, + "id": 32, + "options": { + "displayMode": "basic", + "maxVizHeight": 300, + "minVizHeight": 16, + "minVizWidth": 8, + "namePlacement": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showUnfilled": true, + "sizing": "auto", + "valueMode": "color" + }, + "pluginVersion": "10.4.9", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "rate(promhttp_metric_handler_requests_total{job=\"gateway scrape\", code!=\"200\"}[24h])", + "fullMetaSearch": false, + "includeNullMetadata": false, + "instant": false, + "legendFormat": "Code {{code}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Failed Requests (24h)", + "type": "bargauge" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "gridPos": { + "h": 3, + "w": 12, + "x": 0, + "y": 44 + }, + "id": 34, + "links": [ + { + "targetBlank": true, + "title": "Documentation", + "url": "https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.4.6/api/gateway-service/#monitoring-optional" + } + ], + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "## Optional Panel\n\nActivate this panel by setting-up the Gateway Service Monitoring by clicking the link above.", + "mode": "markdown" + }, + "pluginVersion": "10.4.9", + "transparent": true, + "type": "text" + } + ], + "title": "Gateway", + "type": "row" + } + ], + "refresh": "1m", + "schemaVersion": 39, + "tags": [ + "provisioned", + "dbrepo" + ], + "templating": { + "list": [] + }, + "time": { + "from": "now-30m", + "to": "now" + }, + "timepicker": {}, + "timezone": "browser", + "title": "DBRepo - Overview", + "uid": "bdz20owu8zn5se", + "version": 1, + "weekStart": "" +} \ No newline at end of file diff --git a/dbrepo-dashboard-service/grafana.ini b/dbrepo-dashboard-service/grafana.ini new file mode 100644 index 0000000000000000000000000000000000000000..cc2f5d41a63f1106d0e6b59bba175c4becb16a73 --- /dev/null +++ b/dbrepo-dashboard-service/grafana.ini @@ -0,0 +1,21 @@ +[server] +http_port = 3000 + +[security] +disable_initial_admin_creation = true + +[auth.ldap] +enabled = true +config_file = /etc/grafana/ldap.toml + +[auth.anonymous] +enabled = true +org_role = Viewer +hide_version = true + +[dashboards] +enabled = true +path = /app/dashboards + +#[log] +#filters = ldap:trace \ No newline at end of file diff --git a/dbrepo-dashboard-service/ldap.toml b/dbrepo-dashboard-service/ldap.toml new file mode 100644 index 0000000000000000000000000000000000000000..452353136104eae051526c536631a10a11352216 --- /dev/null +++ b/dbrepo-dashboard-service/ldap.toml @@ -0,0 +1,38 @@ +[[servers]] +host = "identity-service" +port = 1389 +use_ssl = false + +# Search user bind dn +bind_dn = "cn=${LDAP_ADMIN_USERNAME},${LDAP_ROOT}" +bind_password = "${LDAP_ADMIN_PASSWORD}" + +# Timeout in seconds. Applies to each host specified in the 'host' entry (space separated). +timeout = 10 + +# User search filter, for example "(cn=%s)" or "(sAMAccountName=%s)" or "(uid=%s)" +# Allow login from email or username, example "(|(sAMAccountName=%s)(userPrincipalName=%s))" +search_filter = "(cn=%s)" + +# An array of base dns to search through +search_base_dns = ["${LDAP_ROOT}"] + +group_search_base_dns = ["ou=users,${LDAP_ROOT}"] +group_search_filter = "(&(objectClass=groupOfNames)(member=cn=%s,ou=users,${LDAP_ROOT}))" +group_search_filter_user_attribute = "uid" + +[servers.attributes] +name = "givenName" +surname = "sn" +username = "cn" +member_of = "member" +email = "email" + +[[servers.group_mappings]] +group_dn = "cn=${LDAP_ADMIN_USERNAME},ou=users,${LDAP_ROOT}" +org_role = "Admin" +grafana_admin = true + +[[servers.group_mappings]] +group_dn = "*" +org_role = "Viewer" diff --git a/dbrepo-dashboard-service/provisioning/dashboards/provider.yaml b/dbrepo-dashboard-service/provisioning/dashboards/provider.yaml new file mode 100644 index 0000000000000000000000000000000000000000..f54289797de349a240ede871f4d4402fa89214b3 --- /dev/null +++ b/dbrepo-dashboard-service/provisioning/dashboards/provider.yaml @@ -0,0 +1,24 @@ +apiVersion: 1 + +providers: + # <string> an unique provider name. Required + - name: 'dbrepo' + # <int> Org id. Default to 1 + orgId: 1 + # <string> name of the dashboard folder. + folder: '/app/dashboards' + # <string> folder UID. will be automatically generated if not specified + folderUid: '' + # <string> provider type. Default to 'file' + type: file + # <bool> disable dashboard deletion + disableDeletion: false + # <int> how often Grafana will scan for changed dashboards + updateIntervalSeconds: 10 + # <bool> allow updating provisioned dashboards from the UI + allowUiUpdates: false + options: + # <string, required> path to dashboard files on disk. Required when using the 'file' type + path: /app/dashboards + # <bool> use folder names from filesystem to create folders in Grafana + foldersFromFilesStructure: true \ No newline at end of file diff --git a/dbrepo-dashboard-service/provisioning/datasources/prometheus.yaml b/dbrepo-dashboard-service/provisioning/datasources/prometheus.yaml new file mode 100644 index 0000000000000000000000000000000000000000..a46c561957abfd2093e275f213f29f0db7d3fe5c --- /dev/null +++ b/dbrepo-dashboard-service/provisioning/datasources/prometheus.yaml @@ -0,0 +1,7 @@ +apiVersion: 1 + +datasources: + - name: dbrepo-metric-db + type: prometheus + uid: P18F45E9DC7E75912 + url: http://metric-db:9090 diff --git a/dbrepo-data-db/sidecar/Dockerfile b/dbrepo-data-db/sidecar/Dockerfile index 2dfd2a781a746afdbeadc042b548d0719e4acc07..3f849019a413d0add6166dd70a125a9e37be8730 100644 --- a/dbrepo-data-db/sidecar/Dockerfile +++ b/dbrepo-data-db/sidecar/Dockerfile @@ -1,4 +1,5 @@ FROM python:3.11-alpine +LABEL org.opencontainers.image.authors="martin.weise@tuwien.ac.at" RUN apk add bash curl jq mariadb-client diff --git a/dbrepo-data-service/pom.xml b/dbrepo-data-service/pom.xml index fa6f32a02f94b182dbbe3b50ed6385521bcd03cb..6517de47460bdf48ad1f31397a1e67416e3dbc31 100644 --- a/dbrepo-data-service/pom.xml +++ b/dbrepo-data-service/pom.xml @@ -11,7 +11,7 @@ <groupId>at.tuwien</groupId> <artifactId>dbrepo-data-service</artifactId> <name>dbrepo-data-service</name> - <version>1.4.5</version> + <version>1.4.7</version> <description>Service that manages the data</description> @@ -53,6 +53,7 @@ <c3p0-hibernate.version>6.2.2.Final</c3p0-hibernate.version> <aws-s3.version>2.25.23</aws-s3.version> <minio.version>8.5.7</minio.version> + <guava.version>33.3.0-jre</guava.version> </properties> <dependencies> @@ -86,6 +87,11 @@ <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> + <dependency> + <groupId>com.google.guava</groupId> + <artifactId>guava</artifactId> + <version>${guava.version}</version> + </dependency> <!-- Open API --> <dependency> <groupId>org.springdoc</groupId> diff --git a/dbrepo-data-service/querystore/pom.xml b/dbrepo-data-service/querystore/pom.xml index 57bb5dd76ca4f08668eab02c0391ef54a7ea5fa5..c9e016e488737aa458f9c609b0fbd77947fac304 100644 --- a/dbrepo-data-service/querystore/pom.xml +++ b/dbrepo-data-service/querystore/pom.xml @@ -6,12 +6,12 @@ <parent> <groupId>at.tuwien</groupId> <artifactId>dbrepo-data-service</artifactId> - <version>1.4.5</version> + <version>1.4.7</version> </parent> <artifactId>dbrepo-data-service-querystore</artifactId> <name>dbrepo-data-service-querystore</name> - <version>1.4.5</version> + <version>1.4.7</version> <dependencies/> diff --git a/dbrepo-data-service/report/pom.xml b/dbrepo-data-service/report/pom.xml index 10663ef86dfa470e69a0254308d00761af5f7a44..e218cad33215dd52f5171d897704bf74dd7b43a6 100644 --- a/dbrepo-data-service/report/pom.xml +++ b/dbrepo-data-service/report/pom.xml @@ -6,12 +6,12 @@ <parent> <groupId>at.tuwien</groupId> <artifactId>dbrepo-data-service</artifactId> - <version>1.4.5</version> + <version>1.4.7</version> </parent> <artifactId>report</artifactId> <name>dbrepo-data-service-report</name> - <version>1.4.5</version> + <version>1.4.7</version> <description> This module is only intended for the pipeline coverage report. See the detailed report in the respective modules diff --git a/dbrepo-data-service/rest-service/pom.xml b/dbrepo-data-service/rest-service/pom.xml index 9eb7ec933b8a66a8984d900f2382b838e2c6b2d5..eb2ee53fd463b8910faf24b0547f0032598f8c71 100644 --- a/dbrepo-data-service/rest-service/pom.xml +++ b/dbrepo-data-service/rest-service/pom.xml @@ -6,18 +6,18 @@ <parent> <groupId>at.tuwien</groupId> <artifactId>dbrepo-data-service</artifactId> - <version>1.4.5</version> + <version>1.4.7</version> </parent> <artifactId>rest-service</artifactId> <name>dbrepo-data-service-rest-service</name> - <version>1.4.5</version> + <version>1.4.7</version> <dependencies> <dependency> <groupId>at.tuwien</groupId> <artifactId>services</artifactId> - <version>1.4.5</version> + <version>1.4.7</version> </dependency> </dependencies> diff --git a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/AccessEndpoint.java b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/AccessEndpoint.java index 133bee769c792602ae89114a218381dd913f5c93..4059a37a92ba138ef39a6f53365fd70558951e56 100644 --- a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/AccessEndpoint.java +++ b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/AccessEndpoint.java @@ -18,6 +18,7 @@ import jakarta.validation.Valid; import jakarta.validation.constraints.NotBlank; import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; @@ -88,7 +89,7 @@ public class AccessEndpoint { } try { accessService.create(database, user, data.getType()); - return ResponseEntity.accepted() + return ResponseEntity.status(HttpStatus.CREATED) .build(); } catch (SQLException e) { log.error("Failed to establish connection to database: {}", e.getMessage()); diff --git a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/SubsetEndpoint.java b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/SubsetEndpoint.java index a7c74946923a36f639ae692e6d153881bcc2401f..1637878a6785f595a35643471aa2b2b71f027399 100644 --- a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/SubsetEndpoint.java +++ b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/SubsetEndpoint.java @@ -1,7 +1,6 @@ package at.tuwien.endpoints; import at.tuwien.ExportResourceDto; -import at.tuwien.api.database.DatabaseDto; import at.tuwien.api.database.internal.PrivilegedDatabaseDto; import at.tuwien.api.database.query.ExecuteStatementDto; import at.tuwien.api.database.query.QueryDto; @@ -39,6 +38,7 @@ import java.security.Principal; import java.sql.SQLException; import java.time.Instant; import java.util.List; +import java.util.UUID; @Log4j2 @RestController @@ -146,8 +146,7 @@ public class SubsetEndpoint { @RequestParam(required = false) Instant timestamp) throws DatabaseUnavailableException, DatabaseNotFoundException, RemoteUnavailableException, QueryNotFoundException, FormatNotAvailableException, StorageUnavailableException, QueryMalformedException, - SidecarExportException, StorageNotFoundException, NotAllowedException, UserNotFoundException, - MetadataServiceException { + SidecarExportException, StorageNotFoundException, UserNotFoundException, MetadataServiceException { String accept = httpServletRequest.getHeader("Accept"); log.debug("endpoint find subset in database, databaseId={}, subsetId={}, accept={}, timestamp={}", databaseId, subsetId, accept, timestamp); @@ -194,9 +193,8 @@ public class SubsetEndpoint { @PostMapping @Observed(name = "dbrepo_subset_create") - @PreAuthorize("hasAuthority('execute-query')") @Operation(summary = "Create subset", - description = "Creates a subset in the query store of the data database. Requires role `execute-query`", + description = "Creates a subset in the query store of the data database. Requires role `execute-query` for private databases.", security = {@SecurityRequirement(name = "basicAuth"), @SecurityRequirement(name = "bearerAuth")}) @ApiResponses(value = { @ApiResponse(responseCode = "201", @@ -237,7 +235,7 @@ public class SubsetEndpoint { }) public ResponseEntity<QueryResultDto> create(@NotNull @PathVariable("databaseId") Long databaseId, @Valid @RequestBody ExecuteStatementDto data, - @NotNull Principal principal, + Principal principal, @RequestParam(required = false) Long page, @RequestParam(required = false) Long size, @RequestParam(required = false) Instant timestamp) @@ -245,13 +243,14 @@ public class SubsetEndpoint { QueryNotFoundException, StorageUnavailableException, QueryMalformedException, SidecarExportException, StorageNotFoundException, QueryStoreInsertException, TableMalformedException, PaginationException, QueryNotSupportedException, NotAllowedException, UserNotFoundException, MetadataServiceException { - log.debug("endpoint create subset in database, databaseId={}, data.statement={}, principal.name={}, " + - "page={}, size={}, timestamp={}", databaseId, data.getStatement(), principal.getName(), page, size, + log.debug("endpoint create subset in database, databaseId={}, data.statement={}, page={}, size={}, " + + "timestamp={}", databaseId, data.getStatement(), page, size, timestamp); /* check */ endpointValidator.validateDataParams(page, size); endpointValidator.validateForbiddenStatements(data.getStatement()); /* parameters */ + final UUID userId = principal != null ? UserUtil.getId(principal) : null; if (page == null) { page = 0L; log.debug("page not set: default to {}", page); @@ -268,8 +267,8 @@ public class SubsetEndpoint { final PrivilegedDatabaseDto database = metadataServiceGateway.getDatabaseById(databaseId); final QueryResultDto queryResult; try { - queryResult = subsetService.execute(database, data.getStatement(), timestamp, UserUtil.getId(principal), - page, size, null, null); + queryResult = subsetService.execute(database, data.getStatement(), timestamp, userId, page, size, null, + null); } catch (SQLException e) { log.error("Failed to establish connection to database: {}", e.getMessage()); throw new DatabaseUnavailableException("Failed to establish connection to database: " + e.getMessage(), e); @@ -344,9 +343,9 @@ public class SubsetEndpoint { } try { final QueryDto query = subsetService.findById(database, subsetId); - final HttpHeaders headers = new HttpHeaders(); - headers.set("Access-Control-Expose-Headers", "X-Count"); if (request.getMethod().equals("HEAD")) { + final HttpHeaders headers = new HttpHeaders(); + headers.set("Access-Control-Expose-Headers", "X-Count"); final Long count = subsetService.reExecuteCount(database, query); headers.set("X-Count", "" + count); return ResponseEntity.ok() @@ -357,7 +356,6 @@ public class SubsetEndpoint { result.setId(subsetId); log.trace("re-execute query resulted in result {}", result); return ResponseEntity.ok() - .headers(headers) .body(result); } catch (SQLException e) { log.error("Failed to establish connection to database: {}", e.getMessage()); @@ -411,8 +409,8 @@ public class SubsetEndpoint { DatabaseUnavailableException, QueryNotFoundException, UserNotFoundException, MetadataServiceException { log.debug("endpoint persist query, databaseId={}, queryId={}, data.persist={}, principal.name={}", databaseId, queryId, data.getPersist(), principal.getName()); - metadataServiceGateway.getAccess(databaseId, UserUtil.getId(principal)); final PrivilegedDatabaseDto database = metadataServiceGateway.getDatabaseById(databaseId); + metadataServiceGateway.getAccess(databaseId, UserUtil.getId(principal)); try { subsetService.persist(database, queryId, data.getPersist()); final QueryDto dto = subsetService.findById(database, queryId); diff --git a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/TableEndpoint.java b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/TableEndpoint.java index e26a37b43aaa1b5307cf87d294e1dedc5cef87c4..06afef015df02c8077ce312691e140916ea4e2f0 100644 --- a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/TableEndpoint.java +++ b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/TableEndpoint.java @@ -4,8 +4,7 @@ import at.tuwien.ExportResourceDto; import at.tuwien.api.database.DatabaseAccessDto; import at.tuwien.api.database.DatabaseDto; import at.tuwien.api.database.internal.PrivilegedDatabaseDto; -import at.tuwien.api.database.query.ImportCsvDto; -import at.tuwien.api.database.query.QueryDto; +import at.tuwien.api.database.query.ImportDto; import at.tuwien.api.database.query.QueryResultDto; import at.tuwien.api.database.table.*; import at.tuwien.api.database.table.internal.PrivilegedTableDto; @@ -13,6 +12,7 @@ import at.tuwien.api.database.table.internal.TableCreateDto; import at.tuwien.api.error.ApiErrorDto; import at.tuwien.exception.*; import at.tuwien.gateway.MetadataServiceGateway; +import at.tuwien.service.SchemaService; import at.tuwien.service.TableService; import at.tuwien.utils.UserUtil; import at.tuwien.validation.EndpointValidator; @@ -33,7 +33,6 @@ import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.io.InputStreamResource; import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; @@ -51,13 +50,15 @@ import java.util.List; public class TableEndpoint { private final TableService tableService; + private final SchemaService schemaService; private final EndpointValidator endpointValidator; private final MetadataServiceGateway metadataServiceGateway; @Autowired - public TableEndpoint(TableService tableService, EndpointValidator endpointValidator, + public TableEndpoint(TableService tableService, SchemaService schemaService, EndpointValidator endpointValidator, MetadataServiceGateway metadataServiceGateway) { this.tableService = tableService; + this.schemaService = schemaService; this.endpointValidator = endpointValidator; this.metadataServiceGateway = metadataServiceGateway; } @@ -99,10 +100,17 @@ public class TableEndpoint { RemoteUnavailableException, TableMalformedException, DatabaseUnavailableException, TableExistsException, TableNotFoundException, QueryMalformedException, MetadataServiceException { log.debug("endpoint create table, databaseId={}, data.name={}", databaseId, data.getName()); + /* check */ + if (data.getConstraints().getPrimaryKey().isEmpty()) { + log.error("Table must have a primary key"); + throw new TableMalformedException("Table must have a primary key"); + } + /* create */ final PrivilegedDatabaseDto database = metadataServiceGateway.getDatabaseById(databaseId); try { + final TableDto table = tableService.createTable(database, data); return ResponseEntity.status(HttpStatus.CREATED) - .body(tableService.createTable(database, data)); + .body(schemaService.inspectTable(database, table.getInternalName())); } catch (SQLException e) { log.error("Failed to establish connection to database: {}", e.getMessage()); throw new DatabaseUnavailableException("Failed to establish connection to database: " + e.getMessage(), e); @@ -218,13 +226,12 @@ public class TableEndpoint { log.error("Failed find table data: authentication required"); throw new NotAllowedException("Failed to find table data: authentication required"); } - final DatabaseAccessDto access = metadataServiceGateway.getAccess(databaseId, UserUtil.getId(principal)); - endpointValidator.validateOnlyWriteOwnOrWriteAllAccess(access.getType(), table.getOwner().getId(), UserUtil.getId(principal)); + metadataServiceGateway.getAccess(databaseId, UserUtil.getId(principal)); } - final HttpHeaders headers = new HttpHeaders(); - headers.set("Access-Control-Expose-Headers", "X-Count"); try { if (request.getMethod().equals("HEAD")) { + final HttpHeaders headers = new HttpHeaders(); + headers.set("Access-Control-Expose-Headers", "X-Count"); headers.set("X-Count", "" + tableService.getCount(table, timestamp)); return ResponseEntity.ok() .headers(headers) @@ -232,7 +239,6 @@ public class TableEndpoint { } final QueryResultDto dto = tableService.getData(table, timestamp, page, size); return ResponseEntity.ok() - .headers(headers) .body(dto); } catch (SQLException e) { log.error("Failed to establish connection to database: {}", e.getMessage()); @@ -542,14 +548,14 @@ public class TableEndpoint { mediaType = "application/json", schema = @Schema(implementation = ApiErrorDto.class))}), }) - public ResponseEntity<InputStreamResource> exportData(@NotBlank @PathVariable("databaseId") Long databaseId, - @NotBlank @PathVariable("tableId") Long tableId, - @RequestParam(required = false) Instant timestamp, - Principal principal) + public ResponseEntity<InputStreamResource> exportDataset(@NotBlank @PathVariable("databaseId") Long databaseId, + @NotBlank @PathVariable("tableId") Long tableId, + @RequestParam(required = false) Instant timestamp, + Principal principal) throws DatabaseUnavailableException, RemoteUnavailableException, TableNotFoundException, NotAllowedException, StorageUnavailableException, QueryMalformedException, SidecarExportException, StorageNotFoundException, MetadataServiceException { - log.debug("endpoint find table history, databaseId={}, tableId={}, timestamp={}", databaseId, tableId, timestamp); + log.debug("endpoint export table data, databaseId={}, tableId={}, timestamp={}", databaseId, tableId, timestamp); /* parameters */ if (timestamp == null) { timestamp = Instant.now(); @@ -610,7 +616,7 @@ public class TableEndpoint { }) public ResponseEntity<Void> importDataset(@NotBlank @PathVariable("databaseId") Long databaseId, @NotBlank @PathVariable("tableId") Long tableId, - @Valid @RequestBody ImportCsvDto data, + @Valid @RequestBody ImportDto data, @NotNull Principal principal) throws DatabaseUnavailableException, RemoteUnavailableException, TableNotFoundException, QueryMalformedException, StorageNotFoundException, SidecarImportException, NotAllowedException, @@ -619,10 +625,6 @@ public class TableEndpoint { final PrivilegedTableDto table = metadataServiceGateway.getTableById(databaseId, tableId); final DatabaseAccessDto access = metadataServiceGateway.getAccess(databaseId, UserUtil.getId(principal)); endpointValidator.validateOnlyWriteOwnOrWriteAllAccess(access.getType(), table.getOwner().getId(), UserUtil.getId(principal)); - if (data.getNullElement() == null) { - data.setNullElement(""); - log.debug("null element not present, default to empty string"); - } if (data.getLineTermination() == null) { data.setLineTermination("\\r\\n"); log.debug("line termination not present, default to {}", data.getLineTermination()); @@ -672,8 +674,7 @@ public class TableEndpoint { final PrivilegedTableDto table = metadataServiceGateway.getTableById(databaseId, tableId); table.setDatabase(metadataServiceGateway.getDatabaseById(databaseId)); try { - final TableStatisticDto dto = tableService.getStatistics(table); - return ResponseEntity.ok(dto); + return ResponseEntity.ok(tableService.getStatistics(table)); } catch (SQLException e) { log.error("Failed to establish connection to database: {}", e.getMessage()); throw new DatabaseUnavailableException("Failed to establish connection to database", e); diff --git a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/ViewEndpoint.java b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/ViewEndpoint.java index e4ddab603685103027dcb6dfad936b882c987294..9d0bd3b6adec78c34690073a46f35ab220386504 100644 --- a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/ViewEndpoint.java +++ b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/ViewEndpoint.java @@ -1,9 +1,12 @@ package at.tuwien.endpoints; -import at.tuwien.api.database.*; +import at.tuwien.ExportResourceDto; +import at.tuwien.api.database.ViewCreateDto; +import at.tuwien.api.database.ViewDto; import at.tuwien.api.database.internal.PrivilegedDatabaseDto; import at.tuwien.api.database.internal.PrivilegedViewDto; import at.tuwien.api.database.query.QueryResultDto; +import at.tuwien.api.database.table.internal.PrivilegedTableDto; import at.tuwien.api.error.ApiErrorDto; import at.tuwien.exception.*; import at.tuwien.gateway.MetadataServiceGateway; @@ -24,6 +27,7 @@ import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.io.InputStreamResource; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -264,9 +268,9 @@ public class ViewEndpoint { metadataServiceGateway.getAccess(databaseId, UserUtil.getId(principal)); } try { - final HttpHeaders headers = new HttpHeaders(); - headers.set("Access-Control-Expose-Headers", "X-Count"); if (request.getMethod().equals("HEAD")) { + final HttpHeaders headers = new HttpHeaders(); + headers.set("Access-Control-Expose-Headers", "X-Count"); headers.set("X-Count", "" + viewService.count(view, timestamp)); return ResponseEntity.ok() .headers(headers) @@ -275,7 +279,6 @@ public class ViewEndpoint { final QueryResultDto result = viewService.data(view, timestamp, page, size); log.trace("get view data resulted in result {}", result); return ResponseEntity.ok() - .headers(headers) .body(result); } catch (SQLException e) { log.error("Failed to establish connection to database: {}", e.getMessage()); @@ -283,4 +286,67 @@ public class ViewEndpoint { } } + @GetMapping("/{viewId}/export") + @Observed(name = "dbrepo_view_data_export") + @Operation(summary = "Get view data", + description = "Gets data from view with id as downloadable file. For tables in private databases, the user needs to have at least *READ* access to the associated database.", + security = {@SecurityRequirement(name = "basicAuth"), @SecurityRequirement(name = "bearerAuth")}) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", + description = "Exported view data", + content = {@Content( + mediaType = "application/json", + schema = @Schema(implementation = InputStreamResource.class))}), + @ApiResponse(responseCode = "400", + description = "Request pagination or view data select query is malformed", + content = {@Content( + mediaType = "application/json", + schema = @Schema(implementation = ApiErrorDto.class))}), + @ApiResponse(responseCode = "403", + description = "Export view data not allowed", + content = {@Content( + mediaType = "application/json", + schema = @Schema(implementation = ApiErrorDto.class))}), + @ApiResponse(responseCode = "404", + description = "Failed to find view in metadata database or export dataset", + content = {@Content( + mediaType = "application/json", + schema = @Schema(implementation = ApiErrorDto.class))}), + @ApiResponse(responseCode = "503", + description = "Failed to establish connection with the metadata service", + content = {@Content( + mediaType = "application/json", + schema = @Schema(implementation = ApiErrorDto.class))}), + }) + public ResponseEntity<InputStreamResource> exportDataset(@NotBlank @PathVariable("databaseId") Long databaseId, + @NotBlank @PathVariable("viewId") Long viewId, + Principal principal) + throws DatabaseUnavailableException, RemoteUnavailableException, ViewNotFoundException, + NotAllowedException, MetadataServiceException, StorageUnavailableException, QueryMalformedException, + SidecarExportException, StorageNotFoundException { + log.debug("endpoint export view data, databaseId={}, viewId={}", databaseId, viewId); + /* parameters */ + final PrivilegedViewDto view = metadataServiceGateway.getViewById(databaseId, viewId); + if (!view.getIsPublic()) { + if (principal == null) { + log.error("Failed to export private view: principal is null"); + throw new NotAllowedException("Failed to export private view: principal is null"); + } + metadataServiceGateway.getAccess(databaseId, UserUtil.getId(principal)); + } + try { + final HttpHeaders headers = new HttpHeaders(); + final ExportResourceDto resource = viewService.exportDataset(view); + headers.add("Content-Disposition", "attachment; filename=\"" + resource.getFilename() + "\""); + log.trace("export table resulted in resource {}", resource); + return ResponseEntity.ok() + .headers(headers) + .body(resource.getResource()); + + } catch (SQLException e) { + log.error("Failed to establish connection to database: {}", e.getMessage()); + throw new DatabaseUnavailableException("Failed to establish connection to database", e); + } + } + } diff --git a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/handlers/ApiExceptionHandler.java b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/handlers/ApiExceptionHandler.java index cbbb4c76b0c12e7846151746093728212a4d3b8d..6aa48b157082afe6686fccca36b375723cc3b44b 100644 --- a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/handlers/ApiExceptionHandler.java +++ b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/handlers/ApiExceptionHandler.java @@ -21,7 +21,14 @@ public class ApiExceptionHandler extends ResponseEntityExceptionHandler { @ResponseStatus(code = HttpStatus.UNAUTHORIZED) @ExceptionHandler(AccessDeniedException.class) public ResponseEntity<ApiErrorDto> handle(AccessDeniedException e) { - return generic_handle(e.getClass(), e.getLocalizedMessage()); + final HttpHeaders headers = new HttpHeaders(); + headers.set("Content-Type", "application/problem+json"); + final ApiErrorDto response = ApiErrorDto.builder() + .code("error.access.denied") + .message(e.getLocalizedMessage()) + .status(HttpStatus.UNAUTHORIZED) + .build(); + return new ResponseEntity<>(response, headers, HttpStatus.UNAUTHORIZED); } @Hidden @@ -87,6 +94,13 @@ public class ApiExceptionHandler extends ResponseEntityExceptionHandler { return generic_handle(e.getClass(), e.getLocalizedMessage()); } + @Hidden + @ResponseStatus(code = HttpStatus.LOCKED) + @ExceptionHandler(ContainerQuotaException.class) + public ResponseEntity<ApiErrorDto> handle(ContainerQuotaException e) { + return generic_handle(e.getClass(), e.getLocalizedMessage()); + } + @Hidden @ResponseStatus(code = HttpStatus.FORBIDDEN) @ExceptionHandler(CredentialsInvalidException.class) @@ -472,7 +486,7 @@ public class ApiExceptionHandler extends ResponseEntityExceptionHandler { return generic_handle(e.getClass(), e.getLocalizedMessage()); } - private ResponseEntity<ApiErrorDto> generic_handle(Class<?> exceptionClass, String message) { + public ResponseEntity<ApiErrorDto> generic_handle(Class<?> exceptionClass, String message) { final HttpHeaders headers = new HttpHeaders(); headers.set("Content-Type", "application/problem+json"); final ResponseStatus annotation = exceptionClass.getAnnotation(ResponseStatus.class); diff --git a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/validation/EndpointValidator.java b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/validation/EndpointValidator.java index cf868742400bc407c18d57c58984bcae7a7883ca..1c6adfd6a5b87355e76f9b40147fe91f5de4d4e2 100644 --- a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/validation/EndpointValidator.java +++ b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/validation/EndpointValidator.java @@ -1,8 +1,6 @@ package at.tuwien.validation; import at.tuwien.api.database.AccessTypeDto; -import at.tuwien.api.database.DatabaseAccessDto; -import at.tuwien.api.database.DatabaseDto; import at.tuwien.config.QueryConfig; import at.tuwien.exception.NotAllowedException; import at.tuwien.exception.PaginationException; @@ -73,7 +71,7 @@ public class EndpointValidator { log.error("Failed to create table data: insufficient table write access"); throw new NotAllowedException("Failed to create table data: insufficient table write access"); } - log.trace("sufficient write access {}", access); + log.trace("sufficient write access {} for user {} and owner {}", access, user, owner); } diff --git a/dbrepo-data-service/rest-service/src/main/resources/init/querystore.sql b/dbrepo-data-service/rest-service/src/main/resources/init/querystore.sql index c1df44d1b0766fb04d081f3b5b3679039d8ba72f..3e7471df3e1eb3a1bb79db7246ecb805a06f495c 100644 --- a/dbrepo-data-service/rest-service/src/main/resources/init/querystore.sql +++ b/dbrepo-data-service/rest-service/src/main/resources/init/querystore.sql @@ -1,5 +1,5 @@ CREATE SEQUENCE `qs_queries_seq` NOCACHE; -CREATE TABLE `qs_queries` ( `id` bigint not null primary key default nextval(`qs_queries_seq`), `created` datetime not null default now(), `executed` datetime not null default now(), `created_by` varchar(36) not null, `query` text not null, `query_normalized` text not null, `is_persisted` boolean not null, `query_hash` varchar(255) not null, `result_hash` varchar(255), `result_number` bigint ) WITH SYSTEM VERSIONING; +CREATE TABLE `qs_queries` ( `id` bigint not null primary key default nextval(`qs_queries_seq`), `created` datetime not null default now(), `executed` datetime not null default now(), `created_by` varchar(36), `query` text not null, `query_normalized` text not null, `is_persisted` boolean not null, `query_hash` varchar(255) not null, `result_hash` varchar(255), `result_number` bigint ) WITH SYSTEM VERSIONING; CREATE PROCEDURE hash_table(IN name VARCHAR(255), OUT hash VARCHAR(255), OUT count BIGINT) BEGIN DECLARE _sql TEXT; SELECT CONCAT('SELECT SHA2(GROUP_CONCAT(CONCAT_WS(\'\',', GROUP_CONCAT(CONCAT('`', column_name, '`') ORDER BY column_name), ') SEPARATOR \',\'), 256) AS hash, COUNT(*) AS count FROM `', name, '` INTO @hash, @count;') FROM `information_schema`.`columns` WHERE `table_schema` = DATABASE() AND `table_name` = name INTO _sql; PREPARE stmt FROM _sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET hash = @hash; SET count = @count; END; CREATE PROCEDURE store_query(IN query TEXT, IN executed DATETIME, OUT queryId BIGINT) BEGIN DECLARE _queryhash varchar(255) DEFAULT SHA2(query, 256); DECLARE _username varchar(255) DEFAULT REGEXP_REPLACE(current_user(), '@.*', ''); DECLARE _query TEXT DEFAULT CONCAT('CREATE OR REPLACE TABLE _tmp AS (', query, ')'); PREPARE stmt FROM _query; EXECUTE stmt; DEALLOCATE PREPARE stmt; CALL hash_table('_tmp', @hash, @count); DROP TABLE IF EXISTS `_tmp`; IF @hash IS NULL THEN INSERT INTO `qs_queries` (`created_by`, `query`, `query_normalized`, `is_persisted`, `query_hash`, `result_hash`, `result_number`, `executed`) SELECT _username, query, query, false, _queryhash, @hash, @count, executed WHERE NOT EXISTS (SELECT `id` FROM `qs_queries` WHERE `query_hash` = _queryhash AND `result_hash` IS NULL); SET queryId = (SELECT `id` FROM `qs_queries` WHERE `query_hash` = _queryhash AND `result_hash` IS NULL); ELSE INSERT INTO `qs_queries` (`created_by`, `query`, `query_normalized`, `is_persisted`, `query_hash`, `result_hash`, `result_number`, `executed`) SELECT _username, query, query, false, _queryhash, @hash, @count, executed WHERE NOT EXISTS (SELECT `id` FROM `qs_queries` WHERE `query_hash` = _queryhash AND `result_hash` = @hash); SET queryId = (SELECT `id` FROM `qs_queries` WHERE `query_hash` = _queryhash AND `result_hash` = @hash); END IF; END; CREATE DEFINER = 'root' PROCEDURE _store_query(IN _username VARCHAR(255), IN query TEXT, IN executed DATETIME, OUT queryId BIGINT) BEGIN DECLARE _queryhash varchar(255) DEFAULT SHA2(query, 256); DECLARE _query TEXT DEFAULT CONCAT('CREATE OR REPLACE TABLE _tmp AS (', query, ')'); PREPARE stmt FROM _query; EXECUTE stmt; DEALLOCATE PREPARE stmt; CALL hash_table('_tmp', @hash, @count); DROP TABLE IF EXISTS `_tmp`; IF @hash IS NULL THEN INSERT INTO `qs_queries` (`created_by`, `query`, `query_normalized`, `is_persisted`, `query_hash`, `result_hash`, `result_number`, `executed`) SELECT _username, query, query, false, _queryhash, @hash, @count, executed WHERE NOT EXISTS (SELECT `id` FROM `qs_queries` WHERE `query_hash` = _queryhash AND `result_hash` IS NULL); SET queryId = (SELECT `id` FROM `qs_queries` WHERE `query_hash` = _queryhash AND `result_hash` IS NULL); ELSE INSERT INTO `qs_queries` (`created_by`, `query`, `query_normalized`, `is_persisted`, `query_hash`, `result_hash`, `result_number`, `executed`) SELECT _username, query, query, false, _queryhash, @hash, @count, executed WHERE NOT EXISTS (SELECT `id` FROM `qs_queries` WHERE `query_hash` = _queryhash AND `result_hash` = @hash); SET queryId = (SELECT `id` FROM `qs_queries` WHERE `query_hash` = _queryhash AND `result_hash` = @hash); END IF; END; \ No newline at end of file diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/config/MariaDbConfig.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/config/MariaDbConfig.java index 8f73fa1b53b41be7d8cbfbe71f25a27c94ccbb01..691d96006bb273bc257e6439b0f828cae70b9d58 100644 --- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/config/MariaDbConfig.java +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/config/MariaDbConfig.java @@ -6,13 +6,11 @@ import at.tuwien.api.database.internal.PrivilegedDatabaseDto; import at.tuwien.api.database.query.QueryDto; import at.tuwien.api.database.table.columns.ColumnTypeDto; import at.tuwien.api.database.table.internal.PrivilegedTableDto; -import at.tuwien.querystore.Query; import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.ClassPathResource; import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator; -import java.io.IOException; import java.sql.*; import java.time.Instant; import java.util.*; @@ -320,6 +318,27 @@ public class MariaDbConfig { return rows; } + public static List<Map<String, byte[]>> selectQueryByteArr(PrivilegedDatabaseDto database, String query, Set<String> columns) + throws SQLException { + final String jdbc = "jdbc:mariadb://" + database.getContainer().getHost() + ":" + database.getContainer().getPort() + "/" + database.getInternalName(); + log.trace("connect to database {}", jdbc); + final List<Map<String, byte[]>> rows = new LinkedList<>(); + try (Connection connection = DriverManager.getConnection(jdbc, database.getContainer().getUsername(), database.getContainer().getPassword())) { + final Statement statement = connection.createStatement(); + log.trace("execute query: {}", query); + final ResultSet result = statement.executeQuery(query); + log.trace("map result set to columns: {}", columns); + while (result.next()) { + final Map<String, byte[]> row = new HashMap<>(); + for (String column : columns) { + row.put(column, result.getBytes(column)); + } + rows.add(row); + } + } + return rows; + } + public static void execute(PrivilegedDatabaseDto database, String query) throws SQLException { final String jdbc = "jdbc:mariadb://" + database.getContainer().getHost() + ":" + database.getContainer().getPort() + "/" + database.getInternalName(); diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/config/MariaDbContainerConfig.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/config/MariaDbContainerConfig.java index 62f095c82e79df65bd5a9407f735a432dedd502c..74da5a9eb13c6e541f67f660e09e98ea8986a2d0 100644 --- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/config/MariaDbContainerConfig.java +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/config/MariaDbContainerConfig.java @@ -1,11 +1,15 @@ package at.tuwien.config; import at.tuwien.test.BaseTest; +import org.codehaus.plexus.util.FileUtils; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.testcontainers.containers.MariaDBContainer; import org.testcontainers.images.PullPolicy; +import java.io.File; +import java.io.IOException; + /** * This class configures the MariaDB container for the integration tests. */ diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/AccessEndpointUnitTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/AccessEndpointUnitTest.java index 1dc008dbebffdd0a02ef0ffb12a12b9f6e8e6f08..a2cbae3ea89ef15be88121a5ced8c47374601319 100644 --- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/AccessEndpointUnitTest.java +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/AccessEndpointUnitTest.java @@ -1,5 +1,6 @@ package at.tuwien.endpoint; +import at.tuwien.api.database.AccessTypeDto; import at.tuwien.api.database.internal.PrivilegedDatabaseDto; import at.tuwien.api.user.UserDto; import at.tuwien.endpoints.AccessEndpoint; @@ -14,12 +15,14 @@ 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.http.HttpStatus; +import org.springframework.http.ResponseEntity; import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.context.junit.jupiter.SpringExtension; import java.sql.SQLException; -import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; @Log4j2 @@ -53,7 +56,9 @@ public class AccessEndpointUnitTest extends AbstractUnitTest { .thenReturn(USER_4_PRIVILEGED_DTO); /* test */ - accessEndpoint.create(DATABASE_1_ID, USER_4_ID, UPDATE_DATABASE_ACCESS_READ_DTO); + final ResponseEntity<Void> response = accessEndpoint.create(DATABASE_1_ID, USER_4_ID, UPDATE_DATABASE_ACCESS_READ_DTO); + assertEquals(HttpStatus.CREATED, response.getStatusCode()); + assertNull(response.getBody()); } @Test @@ -73,6 +78,26 @@ public class AccessEndpointUnitTest extends AbstractUnitTest { }); } + @Test + @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"}) + public void create_unavailable_fails() throws UserNotFoundException, DatabaseNotFoundException, + RemoteUnavailableException, MetadataServiceException, SQLException, DatabaseMalformedException { + + /* mock */ + when(metadataServiceGateway.getDatabaseById(DATABASE_1_ID)) + .thenReturn(DATABASE_1_PRIVILEGED_DTO); + when(metadataServiceGateway.getPrivilegedUserById(USER_4_ID)) + .thenReturn(USER_4_PRIVILEGED_DTO); + doThrow(SQLException.class) + .when(accessService) + .create(DATABASE_1_PRIVILEGED_DTO, USER_4_PRIVILEGED_DTO, AccessTypeDto.READ); + + /* test */ + assertThrows(DatabaseUnavailableException.class, () -> { + accessEndpoint.create(DATABASE_1_ID, USER_4_ID, UPDATE_DATABASE_ACCESS_READ_DTO); + }); + } + @Test @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"}) public void create_databaseNotFound_fails() throws DatabaseNotFoundException, RemoteUnavailableException, @@ -125,11 +150,50 @@ public class AccessEndpointUnitTest extends AbstractUnitTest { /* mock */ when(metadataServiceGateway.getDatabaseById(DATABASE_1_ID)) .thenReturn(DATABASE_1_PRIVILEGED_DTO); - when(metadataServiceGateway.getPrivilegedUserById(USER_1_ID)) - .thenReturn(USER_1_PRIVILEGED_DTO); + when(metadataServiceGateway.getUserById(USER_1_ID)) + .thenReturn(USER_1_DTO); + + /* test */ + final ResponseEntity<Void> response = accessEndpoint.update(DATABASE_1_ID, USER_1_ID, UPDATE_DATABASE_ACCESS_READ_DTO); + assertEquals(HttpStatus.ACCEPTED, response.getStatusCode()); + assertNull(response.getBody()); + } + + @Test + @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"}) + public void update_unavailable_fails() throws DatabaseNotFoundException, RemoteUnavailableException, SQLException, + UserNotFoundException, DatabaseMalformedException, MetadataServiceException { + + /* mock */ + when(metadataServiceGateway.getDatabaseById(DATABASE_1_ID)) + .thenReturn(DATABASE_1_PRIVILEGED_DTO); + when(metadataServiceGateway.getUserById(USER_1_ID)) + .thenReturn(USER_1_DTO); + doThrow(SQLException.class) + .when(accessService) + .update(DATABASE_1_PRIVILEGED_DTO, USER_1_DTO, AccessTypeDto.READ); /* test */ - accessEndpoint.update(DATABASE_1_ID, USER_1_ID, UPDATE_DATABASE_ACCESS_READ_DTO); + assertThrows(DatabaseUnavailableException.class, () -> { + accessEndpoint.update(DATABASE_1_ID, USER_1_ID, UPDATE_DATABASE_ACCESS_READ_DTO); + }); + } + + @Test + @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"}) + public void update_noAccess_fails() throws DatabaseNotFoundException, RemoteUnavailableException, + UserNotFoundException, MetadataServiceException { + + /* mock */ + when(metadataServiceGateway.getDatabaseById(DATABASE_1_ID)) + .thenReturn(DATABASE_1_PRIVILEGED_DTO); + when(metadataServiceGateway.getUserById(USER_4_ID)) + .thenReturn(USER_4_DTO); + + /* test */ + assertThrows(NotAllowedException.class, () -> { + accessEndpoint.update(DATABASE_1_ID, USER_4_ID, UPDATE_DATABASE_ACCESS_READ_DTO); + }); } @Test @@ -192,7 +256,26 @@ public class AccessEndpointUnitTest extends AbstractUnitTest { .delete(any(PrivilegedDatabaseDto.class), any(UserDto.class)); /* test */ - accessEndpoint.revoke(DATABASE_1_ID, USER_1_ID); + final ResponseEntity<Void> response = accessEndpoint.revoke(DATABASE_1_ID, USER_1_ID); + assertEquals(HttpStatus.ACCEPTED, response.getStatusCode()); + assertNull(response.getBody()); + } + + @Test + @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"}) + public void revoke_noAccess_fails() throws UserNotFoundException, DatabaseNotFoundException, + RemoteUnavailableException, MetadataServiceException { + + /* mock */ + when(metadataServiceGateway.getDatabaseById(DATABASE_1_ID)) + .thenReturn(DATABASE_1_PRIVILEGED_DTO); + when(metadataServiceGateway.getPrivilegedUserById(USER_4_ID)) + .thenReturn(USER_4_PRIVILEGED_DTO); + + /* test */ + assertThrows(NotAllowedException.class, () -> { + accessEndpoint.revoke(DATABASE_1_ID, USER_4_ID); + }); } @Test @@ -239,4 +322,24 @@ public class AccessEndpointUnitTest extends AbstractUnitTest { }); } + @Test + @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"}) + public void revoke_unavailable_fails() throws DatabaseNotFoundException, RemoteUnavailableException, + UserNotFoundException, MetadataServiceException, SQLException, DatabaseMalformedException { + + /* mock */ + when(metadataServiceGateway.getDatabaseById(DATABASE_1_ID)) + .thenReturn(DATABASE_1_PRIVILEGED_DTO); + when(metadataServiceGateway.getUserById(USER_1_ID)) + .thenReturn(USER_1_DTO); + doThrow(SQLException.class) + .when(accessService) + .delete(DATABASE_1_PRIVILEGED_DTO, USER_1_DTO); + + /* test */ + assertThrows(DatabaseUnavailableException.class, () -> { + accessEndpoint.revoke(DATABASE_1_ID, USER_1_ID); + }); + } + } diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/DatabaseEndpointUnitTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/DatabaseEndpointUnitTest.java index c2b04d5aa914b86ef3edde0ebdf5d82f130c1e40..067687c2ed3762481d800c1d1126c074d99c2fe4 100644 --- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/DatabaseEndpointUnitTest.java +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/DatabaseEndpointUnitTest.java @@ -1,6 +1,7 @@ package at.tuwien.endpoint; import at.tuwien.api.database.AccessTypeDto; +import at.tuwien.api.database.DatabaseDto; import at.tuwien.api.user.PrivilegedUserDto; import at.tuwien.endpoints.DatabaseEndpoint; import at.tuwien.exception.*; @@ -16,11 +17,14 @@ 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.http.HttpStatus; +import org.springframework.http.ResponseEntity; import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.context.junit.jupiter.SpringExtension; import java.sql.SQLException; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; @@ -54,10 +58,24 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"}) public void create_succeeds() throws DatabaseUnavailableException, RemoteUnavailableException, - QueryStoreCreateException, ContainerNotFoundException, DatabaseMalformedException, MetadataServiceException { + QueryStoreCreateException, ContainerNotFoundException, DatabaseMalformedException, + MetadataServiceException, SQLException { + + /* mock */ + when(metadataServiceGateway.getContainerById(CONTAINER_1_ID)) + .thenReturn(CONTAINER_1_PRIVILEGED_DTO); + when(databaseService.create(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_CREATE_INTERNAL)) + .thenReturn(DATABASE_1_PRIVILEGED_DTO); + doNothing() + .when(queryService) + .createQueryStore(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_INTERNALNAME); + doNothing() + .when(accessService) + .create(eq(DATABASE_1_PRIVILEGED_DTO), any(PrivilegedUserDto.class), any(AccessTypeDto.class)); /* test */ - databaseEndpoint.create(DATABASE_1_CREATE_INTERNAL); + final ResponseEntity<DatabaseDto> response = databaseEndpoint.create(DATABASE_1_CREATE_INTERNAL); + assertEquals(HttpStatus.CREATED, response.getStatusCode()); } @Test @@ -83,6 +101,24 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest { }); } + @Test + @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"}) + public void create_unavailable_fails() throws RemoteUnavailableException, ContainerNotFoundException, + SQLException, DatabaseMalformedException, MetadataServiceException { + + /* mock */ + when(metadataServiceGateway.getContainerById(CONTAINER_1_ID)) + .thenReturn(CONTAINER_1_PRIVILEGED_DTO); + doThrow(SQLException.class) + .when(databaseService) + .create(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_CREATE_INTERNAL); + + /* test */ + assertThrows(DatabaseUnavailableException.class, () -> { + databaseEndpoint.create(DATABASE_1_CREATE_INTERNAL); + }); + } + @Test @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"}) public void create_containerNotFound_fails() throws RemoteUnavailableException, ContainerNotFoundException, @@ -125,10 +161,32 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest { public void update_succeeds() throws DatabaseUnavailableException, RemoteUnavailableException, DatabaseMalformedException, DatabaseNotFoundException, MetadataServiceException { + /* mock */ + when(metadataServiceGateway.getDatabaseById(DATABASE_1_ID)) + .thenReturn(DATABASE_1_PRIVILEGED_DTO); + /* test */ databaseEndpoint.update(DATABASE_1_ID, USER_1_UPDATE_PASSWORD_DTO); } + @Test + @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"}) + public void update_unavailable_fails() throws RemoteUnavailableException, DatabaseMalformedException, + DatabaseNotFoundException, MetadataServiceException, SQLException { + + /* mock */ + when(metadataServiceGateway.getDatabaseById(DATABASE_1_ID)) + .thenReturn(DATABASE_1_PRIVILEGED_DTO); + doThrow(SQLException.class) + .when(databaseService) + .update(DATABASE_1_PRIVILEGED_DTO, USER_1_UPDATE_PASSWORD_DTO); + + /* test */ + assertThrows(DatabaseUnavailableException.class, () -> { + databaseEndpoint.update(DATABASE_1_ID, USER_1_UPDATE_PASSWORD_DTO); + }); + } + @Test @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME) public void update_noRole_fails() throws RemoteUnavailableException, DatabaseNotFoundException, MetadataServiceException { diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/SubsetEndpointUnitTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/SubsetEndpointUnitTest.java index 6a0015b6f61e567fbf65f2e8f97f6c568fe142fa..9ab7082d0eb40da175947314c13b669de9f02476 100644 --- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/SubsetEndpointUnitTest.java +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/SubsetEndpointUnitTest.java @@ -46,7 +46,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { private SubsetEndpoint subsetEndpoint; @MockBean - private SubsetService queryService; + private SubsetService subsetService; @MockBean private HttpServletRequest httpServletRequest; @@ -64,21 +64,43 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { @Test @WithAnonymousUser - public void findAllById_succeeds() throws DatabaseUnavailableException, NotAllowedException, QueryNotFoundException, + public void list_succeeds() throws DatabaseUnavailableException, NotAllowedException, QueryNotFoundException, DatabaseNotFoundException, RemoteUnavailableException, SQLException, MetadataServiceException { + /* mock */ + when(subsetService.findAll(DATABASE_3_PRIVILEGED_DTO, null)) + .thenReturn(List.of(QUERY_1_DTO, QUERY_2_DTO, QUERY_3_DTO, QUERY_4_DTO, QUERY_5_DTO, QUERY_6_DTO)); + /* test */ - final List<QueryDto> response = generic_findAllById(DATABASE_3_ID, DATABASE_3_PRIVILEGED_DTO); + final List<QueryDto> response = generic_list(DATABASE_3_ID, DATABASE_3_PRIVILEGED_DTO); assertEquals(6, response.size()); } @Test @WithAnonymousUser - public void findAllById_databaseNotFound_fails() { + public void list_databaseNotFound_fails() { /* test */ assertThrows(DatabaseNotFoundException.class, () -> { - generic_findAllById(null, null); + generic_list(null, null); + }); + } + + @Test + @WithAnonymousUser + public void list_unavailable_fails() throws SQLException, QueryNotFoundException, DatabaseNotFoundException, + RemoteUnavailableException, MetadataServiceException { + + /* mock */ + when(metadataServiceGateway.getDatabaseById(DATABASE_3_ID)) + .thenReturn(DATABASE_3_PRIVILEGED_DTO); + doThrow(SQLException.class) + .when(subsetService) + .findAll(DATABASE_3_PRIVILEGED_DTO, null); + + /* test */ + assertThrows(DatabaseUnavailableException.class, () -> { + generic_list(DATABASE_3_ID, DATABASE_3_PRIVILEGED_DTO); }); } @@ -92,9 +114,28 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { /* mock */ when(metadataServiceGateway.getDatabaseById(DATABASE_3_ID)) .thenReturn(DATABASE_3_PRIVILEGED_DTO); + when(subsetService.findById(DATABASE_3_PRIVILEGED_DTO, QUERY_5_ID)) + .thenReturn(QUERY_5_DTO); /* test */ - generic_findById(QUERY_5_ID, QUERY_5_DTO, MediaType.APPLICATION_JSON, null); + generic_findById(QUERY_5_ID, MediaType.APPLICATION_JSON, null); + } + + @Test + @WithAnonymousUser + public void findById_format_fails() throws DatabaseNotFoundException, RemoteUnavailableException, SQLException, + UserNotFoundException, NotAllowedException, QueryNotFoundException, MetadataServiceException { + + /* mock */ + when(metadataServiceGateway.getDatabaseById(DATABASE_3_ID)) + .thenReturn(DATABASE_3_PRIVILEGED_DTO); + when(subsetService.findById(DATABASE_3_PRIVILEGED_DTO, QUERY_5_ID)) + .thenReturn(QUERY_5_DTO); + + /* test */ + assertThrows(FormatNotAvailableException.class, () -> { + generic_findById(QUERY_5_ID, MediaType.APPLICATION_PDF, null); + }); } @Test @@ -111,11 +152,13 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { /* mock */ when(metadataServiceGateway.getDatabaseById(DATABASE_3_ID)) .thenReturn(DATABASE_3_PRIVILEGED_DTO); - when(queryService.export(any(PrivilegedDatabaseDto.class), any(QueryDto.class), any(Instant.class), anyString())) + when(subsetService.findById(DATABASE_3_PRIVILEGED_DTO, QUERY_5_ID)) + .thenReturn(QUERY_5_DTO); + when(subsetService.export(any(PrivilegedDatabaseDto.class), any(QueryDto.class), any(Instant.class), anyString())) .thenReturn(mock); /* test */ - generic_findById(QUERY_5_ID, QUERY_5_DTO, MediaType.parseMediaType("text/csv"), null); + generic_findById(QUERY_5_ID, MediaType.parseMediaType("text/csv"), null); } @Test @@ -132,16 +175,18 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { /* mock */ when(metadataServiceGateway.getDatabaseById(DATABASE_3_ID)) .thenReturn(DATABASE_3_PRIVILEGED_DTO); - when(queryService.export(any(PrivilegedDatabaseDto.class), any(QueryDto.class), any(Instant.class), anyString())) + when(subsetService.findById(DATABASE_3_PRIVILEGED_DTO, QUERY_5_ID)) + .thenReturn(QUERY_5_DTO); + when(subsetService.export(any(PrivilegedDatabaseDto.class), any(QueryDto.class), any(Instant.class), anyString())) .thenReturn(mock); /* test */ - generic_findById(QUERY_5_ID, QUERY_5_DTO, MediaType.parseMediaType("text/csv"), Instant.now()); + generic_findById(QUERY_5_ID, MediaType.parseMediaType("text/csv"), Instant.now()); } @Test @WithAnonymousUser - public void findById_fails() throws DatabaseNotFoundException, RemoteUnavailableException, MetadataServiceException { + public void findById_notFound_fails() throws DatabaseNotFoundException, RemoteUnavailableException, MetadataServiceException { /* mock */ doThrow(DatabaseNotFoundException.class) @@ -150,7 +195,53 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { /* test */ assertThrows(DatabaseNotFoundException.class, () -> { - generic_findById(QUERY_5_ID, QUERY_5_DTO, MediaType.APPLICATION_JSON, null); + generic_findById(QUERY_5_ID, MediaType.APPLICATION_JSON, null); + }); + } + + @Test + @WithAnonymousUser + public void findById_unavailable_fails() throws DatabaseNotFoundException, RemoteUnavailableException, + MetadataServiceException, SQLException, UserNotFoundException, NotAllowedException, QueryNotFoundException { + + /* mock */ + when(metadataServiceGateway.getDatabaseById(DATABASE_3_ID)) + .thenReturn(DATABASE_3_PRIVILEGED_DTO); + doThrow(SQLException.class) + .when(subsetService) + .findById(DATABASE_3_PRIVILEGED_DTO, QUERY_5_ID); + + /* test */ + assertThrows(DatabaseUnavailableException.class, () -> { + generic_findById(QUERY_5_ID, MediaType.APPLICATION_JSON, null); + }); + } + + @Test + @WithAnonymousUser + public void findById_unavailableExport_fails() throws DatabaseNotFoundException, RemoteUnavailableException, + MetadataServiceException, SQLException, StorageUnavailableException, QueryMalformedException, + SidecarExportException, StorageNotFoundException, UserNotFoundException, NotAllowedException, + QueryNotFoundException { + final ExportResourceDto mock = ExportResourceDto.builder() + .filename("deadbeef") + .resource(new InputStreamResource(InputStream.nullInputStream())) + .build(); + + /* mock */ + when(metadataServiceGateway.getDatabaseById(DATABASE_3_ID)) + .thenReturn(DATABASE_3_PRIVILEGED_DTO); + when(subsetService.findById(DATABASE_3_PRIVILEGED_DTO, QUERY_5_ID)) + .thenReturn(QUERY_5_DTO); + when(subsetService.export(any(PrivilegedDatabaseDto.class), any(QueryDto.class), any(Instant.class), anyString())) + .thenReturn(mock); + doThrow(SQLException.class) + .when(subsetService) + .export(eq(DATABASE_3_PRIVILEGED_DTO), eq(QUERY_5_DTO), any(Instant.class), anyString()); + + /* test */ + assertThrows(DatabaseUnavailableException.class, () -> { + generic_findById(QUERY_5_ID, MediaType.parseMediaType("text/csv"), null); }); } @@ -168,7 +259,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { /* mock */ when(metadataServiceGateway.getDatabaseById(DATABASE_3_ID)) .thenReturn(DATABASE_3_PRIVILEGED_DTO); - when(queryService.execute(eq(DATABASE_3_PRIVILEGED_DTO), anyString(), any(Instant.class), eq(USER_1_ID), eq(0L), eq(10L), eq(null), eq(null))) + when(subsetService.execute(eq(DATABASE_3_PRIVILEGED_DTO), anyString(), any(Instant.class), eq(USER_1_ID), eq(0L), eq(10L), eq(null), eq(null))) .thenReturn(QUERY_5_RESULT_DTO); /* test */ @@ -202,13 +293,35 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { /* mock */ when(metadataServiceGateway.getDatabaseById(DATABASE_3_ID)) .thenReturn(DATABASE_3_PRIVILEGED_DTO); - when(queryService.execute(eq(DATABASE_3_PRIVILEGED_DTO), anyString(), any(Instant.class), eq(USER_1_ID), eq(0L), eq(10L), eq(null), eq(null))) + when(subsetService.execute(eq(DATABASE_3_PRIVILEGED_DTO), anyString(), any(Instant.class), eq(USER_1_ID), eq(0L), eq(10L), eq(null), eq(null))) .thenReturn(QUERY_5_RESULT_DTO); /* test */ subsetEndpoint.create(DATABASE_3_ID, request, USER_1_PRINCIPAL, null, null, null); } + @Test + @WithMockUser(username = USER_1_USERNAME, authorities = {"execute-query"}) + public void create_unavailable_succeeds() throws UserNotFoundException, QueryStoreInsertException, + TableMalformedException, NotAllowedException, QueryNotFoundException, DatabaseNotFoundException, + RemoteUnavailableException, SQLException, MetadataServiceException { + final ExecuteStatementDto request = ExecuteStatementDto.builder() + .statement(QUERY_5_STATEMENT) + .build(); + + /* mock */ + when(metadataServiceGateway.getDatabaseById(DATABASE_3_ID)) + .thenReturn(DATABASE_3_PRIVILEGED_DTO); + doThrow(SQLException.class) + .when(subsetService) + .execute(eq(DATABASE_3_PRIVILEGED_DTO), anyString(), any(Instant.class), eq(USER_1_ID), eq(0L), eq(10L), eq(null), eq(null)); + + /* test */ + assertThrows(DatabaseUnavailableException.class, () -> { + subsetEndpoint.create(DATABASE_3_ID, request, USER_1_PRINCIPAL, null, null, null); + }); + } + @Test @WithMockUser(username = USER_1_USERNAME, authorities = {"execute-query"}) public void create_databaseNotFound_fails() throws RemoteUnavailableException, @@ -230,15 +343,36 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_4_USERNAME) - public void create_noRole_fails() { + public void create_noRole_fails() throws DatabaseNotFoundException, RemoteUnavailableException, MetadataServiceException, UserNotFoundException, QueryStoreInsertException, TableMalformedException, NotAllowedException, SQLException, QueryNotFoundException, DatabaseUnavailableException, StorageUnavailableException, QueryMalformedException, SidecarExportException, QueryNotSupportedException, PaginationException, StorageNotFoundException { final ExecuteStatementDto request = ExecuteStatementDto.builder() .statement(QUERY_5_STATEMENT) .build(); + /* mock */ + when(metadataServiceGateway.getDatabaseById(DATABASE_3_ID)) + .thenReturn(DATABASE_3_PRIVILEGED_DTO); + when(subsetService.execute(eq(DATABASE_3_PRIVILEGED_DTO), anyString(), any(Instant.class), eq(USER_4_ID), eq(0L), eq(10L), eq(null), eq(null))) + .thenReturn(QUERY_5_RESULT_DTO); + /* test */ - assertThrows(org.springframework.security.access.AccessDeniedException.class, () -> { - subsetEndpoint.create(DATABASE_3_ID, request, USER_4_PRINCIPAL, null, null, null); - }); + subsetEndpoint.create(DATABASE_3_ID, request, USER_4_PRINCIPAL, null, null, null); + } + + @Test + @WithAnonymousUser + public void create_anonymous_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException, MetadataServiceException, UserNotFoundException, QueryStoreInsertException, TableMalformedException, NotAllowedException, SQLException, QueryNotFoundException, DatabaseUnavailableException, StorageUnavailableException, QueryMalformedException, SidecarExportException, QueryNotSupportedException, PaginationException, StorageNotFoundException { + final ExecuteStatementDto request = ExecuteStatementDto.builder() + .statement(QUERY_5_STATEMENT) + .build(); + + /* mock */ + when(metadataServiceGateway.getDatabaseById(DATABASE_3_ID)) + .thenReturn(DATABASE_3_PRIVILEGED_DTO); + when(subsetService.execute(eq(DATABASE_3_PRIVILEGED_DTO), anyString(), any(Instant.class), eq(null), eq(0L), eq(10L), eq(null), eq(null))) + .thenReturn(QUERY_5_RESULT_DTO); + + /* test */ + subsetEndpoint.create(DATABASE_3_ID, request, null, null, null, null); } @Test @@ -249,11 +383,11 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { /* mock */ when(metadataServiceGateway.getDatabaseById(DATABASE_3_ID)) .thenReturn(DATABASE_3_PRIVILEGED_DTO); - when(queryService.findById(DATABASE_3_PRIVILEGED_DTO, QUERY_5_ID)) + when(subsetService.findById(DATABASE_3_PRIVILEGED_DTO, QUERY_5_ID)) .thenReturn(QUERY_5_DTO); - when(queryService.reExecuteCount(DATABASE_3_PRIVILEGED_DTO, QUERY_5_DTO)) + when(subsetService.reExecuteCount(DATABASE_3_PRIVILEGED_DTO, QUERY_5_DTO)) .thenReturn(QUERY_5_RESULT_NUMBER); - when(queryService.reExecute(DATABASE_3_PRIVILEGED_DTO, QUERY_5_DTO, 0L, 10L, null, null)) + when(subsetService.reExecute(DATABASE_3_PRIVILEGED_DTO, QUERY_5_DTO, 0L, 10L, null, null)) .thenReturn(QUERY_5_RESULT_DTO); when(httpServletRequest.getMethod()) .thenReturn("GET"); @@ -261,23 +395,20 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { /* test */ final ResponseEntity<QueryResultDto> response = subsetEndpoint.getData(DATABASE_3_ID, QUERY_5_ID, null, httpServletRequest, null, null); assertEquals(HttpStatus.OK, response.getStatusCode()); - assertNotNull(response.getHeaders().get("Access-Control-Expose-Headers")); - assertEquals(1, response.getHeaders().get("Access-Control-Expose-Headers").size()); - assertEquals("X-Count", response.getHeaders().get("Access-Control-Expose-Headers").get(0)); assertNotNull(response.getBody()); } @Test - public void getData_onlyHead_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException, UserNotFoundException, + public void getData_head_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException, UserNotFoundException, NotAllowedException, SQLException, QueryNotFoundException, TableMalformedException, QueryMalformedException, DatabaseUnavailableException, PaginationException, MetadataServiceException { /* mock */ when(metadataServiceGateway.getDatabaseById(DATABASE_3_ID)) .thenReturn(DATABASE_3_PRIVILEGED_DTO); - when(queryService.findById(DATABASE_3_PRIVILEGED_DTO, QUERY_5_ID)) + when(subsetService.findById(DATABASE_3_PRIVILEGED_DTO, QUERY_5_ID)) .thenReturn(QUERY_5_DTO); - when(queryService.reExecuteCount(DATABASE_3_PRIVILEGED_DTO, QUERY_5_DTO)) + when(subsetService.reExecuteCount(DATABASE_3_PRIVILEGED_DTO, QUERY_5_DTO)) .thenReturn(QUERY_5_RESULT_NUMBER); when(httpServletRequest.getMethod()) .thenReturn("HEAD"); @@ -301,11 +432,11 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { .thenReturn(DATABASE_1_PRIVILEGED_DTO); when(httpServletRequest.getMethod()) .thenReturn("GET"); - when(queryService.findById(DATABASE_1_PRIVILEGED_DTO, QUERY_1_ID)) + when(subsetService.findById(DATABASE_1_PRIVILEGED_DTO, QUERY_1_ID)) .thenReturn(QUERY_1_DTO); - when(queryService.reExecuteCount(DATABASE_1_PRIVILEGED_DTO, QUERY_1_DTO)) + when(subsetService.reExecuteCount(DATABASE_1_PRIVILEGED_DTO, QUERY_1_DTO)) .thenReturn(QUERY_1_RESULT_NUMBER); - when(queryService.reExecute(DATABASE_1_PRIVILEGED_DTO, QUERY_1_DTO, 0L, 10L, null, null)) + when(subsetService.reExecute(DATABASE_1_PRIVILEGED_DTO, QUERY_1_DTO, 0L, 10L, null, null)) .thenReturn(QUERY_1_RESULT_DTO); /* test */ @@ -349,16 +480,16 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_1_USERNAME) - public void getData_privateOnlyHead_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException, + public void getData_privateHead_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException, UserNotFoundException, DatabaseUnavailableException, NotAllowedException, TableMalformedException, QueryMalformedException, QueryNotFoundException, PaginationException, SQLException, MetadataServiceException { /* mock */ when(metadataServiceGateway.getDatabaseById(DATABASE_1_ID)) .thenReturn(DATABASE_1_PRIVILEGED_DTO); - when(queryService.findById(DATABASE_1_PRIVILEGED_DTO, QUERY_1_ID)) + when(subsetService.findById(DATABASE_1_PRIVILEGED_DTO, QUERY_1_ID)) .thenReturn(QUERY_1_DTO); - when(queryService.reExecuteCount(DATABASE_1_PRIVILEGED_DTO, QUERY_1_DTO)) + when(subsetService.reExecuteCount(DATABASE_1_PRIVILEGED_DTO, QUERY_1_DTO)) .thenReturn(QUERY_1_RESULT_NUMBER); when(httpServletRequest.getMethod()) .thenReturn("HEAD"); @@ -371,6 +502,29 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { assertEquals(QUERY_1_RESULT_NUMBER, Long.parseLong(response.getHeaders().get("X-Count").get(0))); } + @Test + @WithMockUser(username = USER_1_USERNAME) + public void getData_unavailable_fails() throws DatabaseNotFoundException, RemoteUnavailableException, SQLException, + UserNotFoundException, NotAllowedException, TableMalformedException, QueryNotFoundException, + MetadataServiceException { + + /* mock */ + when(metadataServiceGateway.getDatabaseById(DATABASE_1_ID)) + .thenReturn(DATABASE_1_PRIVILEGED_DTO); + when(subsetService.findById(DATABASE_1_PRIVILEGED_DTO, QUERY_1_ID)) + .thenReturn(QUERY_1_DTO); + when(httpServletRequest.getMethod()) + .thenReturn("GET"); + doThrow(SQLException.class) + .when(subsetService) + .reExecute(DATABASE_1_PRIVILEGED_DTO, QUERY_1_DTO, 0L, 10L, null, null); + + /* test */ + assertThrows(DatabaseUnavailableException.class, () -> { + subsetEndpoint.getData(DATABASE_1_ID, QUERY_1_ID, USER_1_PRINCIPAL, httpServletRequest, null, null); + }); + } + @Test @WithMockUser(username = USER_3_USERNAME, authorities = {"persist-query"}) public void persist_succeeds() throws NotAllowedException, RemoteUnavailableException, DatabaseNotFoundException, @@ -386,9 +540,9 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { when(metadataServiceGateway.getDatabaseById(DATABASE_3_ID)) .thenReturn(DATABASE_3_PRIVILEGED_DTO); doNothing() - .when(queryService) + .when(subsetService) .persist(DATABASE_3_PRIVILEGED_DTO, QUERY_5_ID, true); - when(queryService.findById(DATABASE_3_PRIVILEGED_DTO, QUERY_5_ID)) + when(subsetService.findById(DATABASE_3_PRIVILEGED_DTO, QUERY_5_ID)) .thenReturn(QUERY_5_DTO); /* test */ @@ -447,16 +601,37 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { }); } - protected List<QueryDto> generic_findAllById(Long databaseId, PrivilegedDatabaseDto database) - throws DatabaseUnavailableException, NotAllowedException, QueryNotFoundException, DatabaseNotFoundException, - RemoteUnavailableException, SQLException, MetadataServiceException { + @Test + @WithMockUser(username = USER_3_USERNAME, authorities = {"persist-query"}) + public void persist_unavailable_fails() throws NotAllowedException, RemoteUnavailableException, + MetadataServiceException, QueryStorePersistException, SQLException, DatabaseNotFoundException { + final QueryPersistDto request = QueryPersistDto.builder() + .persist(true) + .build(); + + /* mock */ + when(metadataServiceGateway.getDatabaseById(DATABASE_3_ID)) + .thenReturn(DATABASE_3_PRIVILEGED_DTO); + when(metadataServiceGateway.getAccess(DATABASE_3_ID, USER_3_ID)) + .thenReturn(DATABASE_3_USER_3_READ_ACCESS_DTO); + doThrow(SQLException.class) + .when(subsetService) + .persist(DATABASE_3_PRIVILEGED_DTO, QUERY_5_ID, true); + + /* test */ + assertThrows(DatabaseUnavailableException.class, () -> { + subsetEndpoint.persist(DATABASE_3_ID, QUERY_5_ID, request, USER_3_PRINCIPAL); + }); + } + + protected List<QueryDto> generic_list(Long databaseId, PrivilegedDatabaseDto database) throws NotAllowedException, + DatabaseUnavailableException, QueryNotFoundException, DatabaseNotFoundException, RemoteUnavailableException, + MetadataServiceException { /* mock */ if (database != null) { when(metadataServiceGateway.getDatabaseById(databaseId)) .thenReturn(database); - when(queryService.findAll(database, null)) - .thenReturn(List.of(QUERY_1_DTO, QUERY_2_DTO, QUERY_3_DTO, QUERY_4_DTO, QUERY_5_DTO, QUERY_6_DTO)); } else { doThrow(DatabaseNotFoundException.class) .when(metadataServiceGateway) @@ -469,15 +644,12 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { return response.getBody(); } - protected void generic_findById(Long subsetId, QueryDto subset, MediaType accept, Instant timestamp) - throws UserNotFoundException, DatabaseUnavailableException, StorageUnavailableException, - NotAllowedException, QueryMalformedException, QueryNotFoundException, DatabaseNotFoundException, - SidecarExportException, RemoteUnavailableException, FormatNotAvailableException, StorageNotFoundException, - SQLException, MetadataServiceException { + protected void generic_findById(Long subsetId, MediaType accept, Instant timestamp) throws UserNotFoundException, + DatabaseUnavailableException, StorageUnavailableException, NotAllowedException, QueryMalformedException, + QueryNotFoundException, DatabaseNotFoundException, SidecarExportException, RemoteUnavailableException, + FormatNotAvailableException, StorageNotFoundException, MetadataServiceException { /* mock */ - when(queryService.findById(DATABASE_3_PRIVILEGED_DTO, subsetId)) - .thenReturn(subset); when(mockHttpServletRequest.getHeader("Accept")) .thenReturn(accept.toString()); diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/TableEndpointUnitTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/TableEndpointUnitTest.java index 76c34ef47cd2d13f698f3d552b9aebbbb4175492..cc4b957226a77fbe4f39aef09193b29def575959 100644 --- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/TableEndpointUnitTest.java +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/TableEndpointUnitTest.java @@ -1,12 +1,15 @@ package at.tuwien.endpoint; import at.tuwien.ExportResourceDto; -import at.tuwien.api.database.query.ImportCsvDto; +import at.tuwien.api.database.DatabaseAccessDto; +import at.tuwien.api.database.query.ImportDto; import at.tuwien.api.database.query.QueryResultDto; import at.tuwien.api.database.table.*; +import at.tuwien.api.database.table.internal.PrivilegedTableDto; import at.tuwien.endpoints.TableEndpoint; import at.tuwien.exception.*; import at.tuwien.gateway.MetadataServiceGateway; +import at.tuwien.service.SchemaService; import at.tuwien.service.TableService; import at.tuwien.test.AbstractUnitTest; import jakarta.servlet.http.HttpServletRequest; @@ -14,12 +17,16 @@ import lombok.extern.log4j.Log4j2; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; 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.core.io.InputStreamResource; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.security.access.AccessDeniedException; import org.springframework.security.test.context.support.WithAnonymousUser; import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.context.junit.jupiter.SpringExtension; @@ -29,6 +36,7 @@ import java.sql.SQLException; import java.time.Instant; import java.util.HashMap; import java.util.List; +import java.util.stream.Stream; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; @@ -47,9 +55,28 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @MockBean private TableService tableService; + @MockBean + private SchemaService schemaService; + @MockBean private MetadataServiceGateway metadataServiceGateway; + public static Stream<Arguments> size_arguments() { + return Stream.of( + Arguments.arguments("zero", 0L), + Arguments.arguments("neg zero", -0L), + Arguments.arguments("negative", -1L) + ); + } + + public static Stream<Arguments> anyAccess_parameters() { + return Stream.of( + Arguments.arguments("read", DATABASE_1_USER_2_READ_ACCESS_DTO), + Arguments.arguments("write_own", DATABASE_1_USER_2_WRITE_OWN_ACCESS_DTO), + Arguments.arguments("write_all", DATABASE_1_USER_2_WRITE_ALL_ACCESS_DTO) + ); + } + @BeforeEach public void beforeEach() { genesis(); @@ -66,6 +93,8 @@ public class TableEndpointUnitTest extends AbstractUnitTest { .thenReturn(DATABASE_1_PRIVILEGED_DTO); when(tableService.createTable(DATABASE_1_PRIVILEGED_DTO, TABLE_4_CREATE_INTERNAL_DTO)) .thenReturn(TABLE_4_DTO); + when(schemaService.inspectTable(DATABASE_1_PRIVILEGED_DTO, TABLE_4_INTERNALNAME)) + .thenReturn(TABLE_4_DTO); /* test */ final ResponseEntity<TableDto> response = tableEndpoint.create(DATABASE_1_ID, TABLE_4_CREATE_INTERNAL_DTO); @@ -98,6 +127,85 @@ public class TableEndpointUnitTest extends AbstractUnitTest { }); } + @Test + @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"}) + public void create_unavailable_fails() throws TableMalformedException, DatabaseNotFoundException, SQLException, + TableExistsException, RemoteUnavailableException, TableNotFoundException, MetadataServiceException { + + /* mock */ + when(metadataServiceGateway.getDatabaseById(DATABASE_1_ID)) + .thenReturn(DATABASE_1_PRIVILEGED_DTO); + doThrow(SQLException.class) + .when(tableService) + .createTable(DATABASE_1_PRIVILEGED_DTO, TABLE_4_CREATE_INTERNAL_DTO); + + /* test */ + assertThrows(DatabaseUnavailableException.class, () -> { + tableEndpoint.create(DATABASE_1_ID, TABLE_4_CREATE_INTERNAL_DTO); + }); + } + + @Test + @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"}) + public void create_missingPrimaryKey_fails() { + + /* test */ + assertThrows(TableMalformedException.class, () -> { + tableEndpoint.create(DATABASE_1_ID, TABLE_1_CREATE_INTERNAL_INVALID_DTO); + }); + } + + @Test + @WithAnonymousUser + public void statistic_succeeds() throws DatabaseUnavailableException, TableNotFoundException, + TableMalformedException, DatabaseNotFoundException, RemoteUnavailableException, MetadataServiceException, + SQLException { + + /* mock */ + when(metadataServiceGateway.getTableById(DATABASE_3_ID, TABLE_8_ID)) + .thenReturn(TABLE_8_PRIVILEGED_DTO); + when(tableService.getStatistics(any(PrivilegedTableDto.class))) + .thenReturn(TABLE_8_STATISTIC_DTO); + + /* test */ + final ResponseEntity<TableStatisticDto> response = tableEndpoint.statistic(DATABASE_3_ID, TABLE_8_ID); + assertEquals(HttpStatus.OK, response.getStatusCode()); + } + + @Test + @WithAnonymousUser + public void statistic_unavailable_fails() throws TableNotFoundException, TableMalformedException, + RemoteUnavailableException, MetadataServiceException, SQLException { + + /* mock */ + when(metadataServiceGateway.getTableById(DATABASE_3_ID, TABLE_8_ID)) + .thenReturn(TABLE_8_PRIVILEGED_DTO); + doThrow(SQLException.class) + .when(tableService) + .getStatistics(any(PrivilegedTableDto.class)); + + /* test */ + assertThrows(DatabaseUnavailableException.class, () -> { + tableEndpoint.statistic(DATABASE_3_ID, TABLE_8_ID); + }); + } + + @Test + @WithAnonymousUser + public void statistic_notFound_fails() throws TableNotFoundException, RemoteUnavailableException, + MetadataServiceException { + + /* mock */ + doThrow(TableNotFoundException.class) + .when(metadataServiceGateway) + .getTableById(DATABASE_1_ID, TABLE_1_ID); + + /* test */ + assertThrows(TableNotFoundException.class, () -> { + tableEndpoint.statistic(DATABASE_1_ID, TABLE_1_ID); + }); + } + @Test @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"}) public void delete_succeeds() throws RemoteUnavailableException, DatabaseUnavailableException, @@ -141,6 +249,24 @@ public class TableEndpointUnitTest extends AbstractUnitTest { }); } + @Test + @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"}) + public void delete_unavailable_fails() throws RemoteUnavailableException, TableNotFoundException, SQLException, + MetadataServiceException, QueryMalformedException { + + /* mock */ + when(metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_1_ID)) + .thenReturn(TABLE_1_PRIVILEGED_DTO); + doThrow(SQLException.class) + .when(tableService) + .delete(TABLE_1_PRIVILEGED_DTO); + + /* test */ + assertThrows(DatabaseUnavailableException.class, () -> { + tableEndpoint.delete(DATABASE_1_ID, TABLE_1_ID); + }); + } + @Test @WithAnonymousUser public void getData_succeeds() throws DatabaseUnavailableException, TableNotFoundException, TableMalformedException, @@ -150,18 +276,129 @@ public class TableEndpointUnitTest extends AbstractUnitTest { /* mock */ when(metadataServiceGateway.getTableById(DATABASE_3_ID, TABLE_8_ID)) .thenReturn(TABLE_8_PRIVILEGED_DTO); - when(tableService.getCount(eq(TABLE_8_PRIVILEGED_DTO), any(Instant.class))) - .thenReturn(TABLE_8_DATA_COUNT); when(tableService.getData(eq(TABLE_8_PRIVILEGED_DTO), any(Instant.class), eq(0L), eq(10L))) .thenReturn(TABLE_8_DATA_DTO); /* test */ final ResponseEntity<QueryResultDto> response = tableEndpoint.getData(DATABASE_3_ID, TABLE_8_ID, null, null, null, httpServletRequest, null); assertEquals(HttpStatus.OK, response.getStatusCode()); + + } + + @Test + @WithAnonymousUser + public void getData_head_succeeds() throws DatabaseUnavailableException, TableNotFoundException, TableMalformedException, + SQLException, QueryMalformedException, RemoteUnavailableException, PaginationException, MetadataServiceException, + NotAllowedException { + final HttpServletRequest mock = mock(HttpServletRequest.class); + + /* mock */ + when(metadataServiceGateway.getTableById(DATABASE_3_ID, TABLE_8_ID)) + .thenReturn(TABLE_8_PRIVILEGED_DTO); + when(mock.getMethod()) + .thenReturn("HEAD"); + when(tableService.getCount(eq(TABLE_8_PRIVILEGED_DTO), any(Instant.class))) + .thenReturn(3L); + when(tableService.getData(eq(TABLE_8_PRIVILEGED_DTO), any(Instant.class), eq(0L), eq(10L))) + .thenReturn(TABLE_8_DATA_DTO); + + /* test */ + final ResponseEntity<QueryResultDto> response = tableEndpoint.getData(DATABASE_3_ID, TABLE_8_ID, null, null, null, mock, null); + assertEquals(HttpStatus.OK, response.getStatusCode()); assertNotNull(response.getHeaders().get("Access-Control-Expose-Headers")); - assertEquals(1, response.getHeaders().get("Access-Control-Expose-Headers").size()); assertEquals("X-Count", response.getHeaders().get("Access-Control-Expose-Headers").get(0)); + assertNotNull(response.getHeaders().get("X-Count")); + assertEquals("3", response.getHeaders().get("X-Count").get(0)); + + } + + @Test + @WithAnonymousUser + public void getData_privateAnonymous_fails() throws TableNotFoundException, RemoteUnavailableException, + MetadataServiceException { + /* mock */ + when(metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_1_ID)) + .thenReturn(TABLE_1_PRIVILEGED_DTO); + + /* test */ + assertThrows(NotAllowedException.class, () -> { + tableEndpoint.getData(DATABASE_1_ID, TABLE_1_ID, null, null, null, httpServletRequest, null); + }); + } + + @Test + @WithMockUser(username = USER_2_USERNAME) + public void getData_privateNoAccess_fails() throws TableNotFoundException, RemoteUnavailableException, + MetadataServiceException, NotAllowedException { + + /* mock */ + when(metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_1_ID)) + .thenReturn(TABLE_1_PRIVILEGED_DTO); + doThrow(NotAllowedException.class) + .when(metadataServiceGateway) + .getAccess(DATABASE_1_ID, USER_2_ID); + + /* test */ + assertThrows(NotAllowedException.class, () -> { + tableEndpoint.getData(DATABASE_1_ID, TABLE_1_ID, null, null, null, httpServletRequest, USER_2_PRINCIPAL); + }); + } + + @Test + @WithAnonymousUser + public void getData_unavailable_fails() throws TableNotFoundException, RemoteUnavailableException, + MetadataServiceException, TableMalformedException, SQLException { + + /* mock */ + when(metadataServiceGateway.getTableById(DATABASE_3_ID, TABLE_8_ID)) + .thenReturn(TABLE_8_PRIVILEGED_DTO); + doThrow(SQLException.class) + .when(tableService) + .getData(eq(TABLE_8_PRIVILEGED_DTO), any(Instant.class), eq(0L), eq(10L)); + + /* test */ + assertThrows(DatabaseUnavailableException.class, () -> { + tableEndpoint.getData(DATABASE_3_ID, TABLE_8_ID, null, null, null, httpServletRequest, null); + }); + } + + @Test + @WithMockUser(username = USER_2_USERNAME) + public void getData_privateAccessUnavailable_fails() throws TableNotFoundException, RemoteUnavailableException, + MetadataServiceException, NotAllowedException { + + /* mock */ + when(metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_1_ID)) + .thenReturn(TABLE_1_PRIVILEGED_DTO); + doThrow(RemoteUnavailableException.class) + .when(metadataServiceGateway) + .getAccess(DATABASE_1_ID, USER_2_ID); + + /* test */ + assertThrows(RemoteUnavailableException.class, () -> { + tableEndpoint.getData(DATABASE_1_ID, TABLE_1_ID, null, null, null, httpServletRequest, USER_2_PRINCIPAL); + }); + } + + @ParameterizedTest + @WithMockUser(username = USER_2_USERNAME) + @MethodSource("anyAccess_parameters") + public void getData_private_succeeds(String name, DatabaseAccessDto access) throws DatabaseUnavailableException, + TableNotFoundException, TableMalformedException, SQLException, QueryMalformedException, + RemoteUnavailableException, PaginationException, MetadataServiceException, NotAllowedException { + + /* mock */ + when(metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_1_ID)) + .thenReturn(TABLE_1_PRIVILEGED_DTO); + when(metadataServiceGateway.getAccess(DATABASE_1_ID, USER_2_ID)) + .thenReturn(access); + when(tableService.getData(eq(TABLE_1_PRIVILEGED_DTO), any(Instant.class), eq(0L), eq(10L))) + .thenReturn(TABLE_1_DATA_DTO); + + /* test */ + final ResponseEntity<QueryResultDto> response = tableEndpoint.getData(DATABASE_1_ID, TABLE_1_ID, null, null, null, httpServletRequest, USER_2_PRINCIPAL); + assertEquals(HttpStatus.OK, response.getStatusCode()); } @Test @@ -182,7 +419,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_1_USERNAME, authorities = {"insert-table-data"}) - public void createTuple_succeeds() throws DatabaseUnavailableException, TableNotFoundException, + public void insertRawTuple_succeeds() throws DatabaseUnavailableException, TableNotFoundException, TableMalformedException, NotAllowedException, QueryMalformedException, RemoteUnavailableException, SQLException, StorageUnavailableException, StorageNotFoundException, MetadataServiceException { final TupleDto request = TupleDto.builder() @@ -211,7 +448,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_3_USERNAME) - public void createTuple_noRole_fails() { + public void insertRawTuple_noRole_fails() { final TupleDto request = TupleDto.builder() .data(new HashMap<>() {{ put(COLUMN_8_1_INTERNAL_NAME, 7L); @@ -227,7 +464,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"}) - public void createTuple_tableNotFound_fails() throws TableNotFoundException, RemoteUnavailableException, + public void insertRawTuple_tableNotFound_fails() throws TableNotFoundException, RemoteUnavailableException, MetadataServiceException { final TupleDto request = TupleDto.builder() .data(new HashMap<>() {{ @@ -249,7 +486,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"}) - public void createTuple_readAccess_fails() throws TableNotFoundException, RemoteUnavailableException, + public void insertRawTuple_readAccess_fails() throws TableNotFoundException, RemoteUnavailableException, NotAllowedException, MetadataServiceException { final TupleDto request = TupleDto.builder() .data(new HashMap<>() {{ @@ -270,9 +507,36 @@ public class TableEndpointUnitTest extends AbstractUnitTest { }); } + @Test + @WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"}) + public void insertRawTuple_unavailable_fails() throws TableNotFoundException, RemoteUnavailableException, + NotAllowedException, MetadataServiceException, TableMalformedException, StorageUnavailableException, + SQLException, QueryMalformedException, StorageNotFoundException { + final TupleDto request = TupleDto.builder() + .data(new HashMap<>() {{ + put(COLUMN_8_1_INTERNAL_NAME, 7L); + put(COLUMN_8_2_INTERNAL_NAME, 23.0); + }}) + .build(); + + /* mock */ + when(metadataServiceGateway.getTableById(DATABASE_3_ID, TABLE_8_ID)) + .thenReturn(TABLE_8_PRIVILEGED_DTO); + when(metadataServiceGateway.getAccess(DATABASE_3_ID, USER_1_ID)) + .thenReturn(DATABASE_3_USER_1_WRITE_OWN_ACCESS_DTO); + doThrow(SQLException.class) + .when(tableService) + .createTuple(TABLE_8_PRIVILEGED_DTO, request); + + /* test */ + assertThrows(DatabaseUnavailableException.class, () -> { + tableEndpoint.insertRawTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_1_PRINCIPAL); + }); + } + @Test @WithMockUser(username = USER_1_USERNAME, authorities = {"insert-table-data"}) - public void createTuple_writeOwnAccess_succeeds() throws TableNotFoundException, RemoteUnavailableException, + public void insertRawTuple_writeOwnAccess_succeeds() throws TableNotFoundException, RemoteUnavailableException, NotAllowedException, DatabaseUnavailableException, TableMalformedException, QueryMalformedException, StorageUnavailableException, StorageNotFoundException, MetadataServiceException { final TupleDto request = TupleDto.builder() @@ -294,7 +558,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"}) - public void createTuple_writeOwnAccessForeign_fails() throws TableNotFoundException, RemoteUnavailableException, + public void insertRawTuple_writeOwnAccessForeign_fails() throws TableNotFoundException, RemoteUnavailableException, NotAllowedException, MetadataServiceException { final TupleDto request = TupleDto.builder() .data(new HashMap<>() {{ @@ -317,7 +581,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"}) - public void createTuple_writeAllAccessForeign_succeeds() throws TableNotFoundException, RemoteUnavailableException, + public void insertRawTuple_writeAllAccessForeign_succeeds() throws TableNotFoundException, RemoteUnavailableException, NotAllowedException, DatabaseUnavailableException, TableMalformedException, QueryMalformedException, StorageUnavailableException, StorageNotFoundException, MetadataServiceException { final TupleDto request = TupleDto.builder() @@ -439,6 +703,35 @@ public class TableEndpointUnitTest extends AbstractUnitTest { }); } + @Test + @WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"}) + public void updateTuple_unavailable_fails() throws TableNotFoundException, RemoteUnavailableException, SQLException, + NotAllowedException, MetadataServiceException, TableMalformedException, QueryMalformedException { + final TupleUpdateDto request = TupleUpdateDto.builder() + .keys(new HashMap<>() {{ + put(COLUMN_8_1_INTERNAL_NAME, 6L); + }}) + .data(new HashMap<>() {{ + put(COLUMN_8_1_INTERNAL_NAME, 6L); + put(COLUMN_8_2_INTERNAL_NAME, 23.0); + }}) + .build(); + + /* mock */ + when(metadataServiceGateway.getTableById(DATABASE_3_ID, TABLE_8_ID)) + .thenReturn(TABLE_8_PRIVILEGED_DTO); + when(metadataServiceGateway.getAccess(DATABASE_3_ID, USER_3_ID)) + .thenReturn(DATABASE_3_USER_3_WRITE_ALL_ACCESS_DTO); + doThrow(SQLException.class) + .when(tableService) + .updateTuple(TABLE_8_PRIVILEGED_DTO, request); + + /* test */ + assertThrows(DatabaseUnavailableException.class, () -> { + tableEndpoint.updateRawTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL); + }); + } + @Test @WithMockUser(username = USER_1_USERNAME, authorities = {"insert-table-data"}) public void updateTuple_writeOwnAccess_succeeds() throws DatabaseUnavailableException, TableNotFoundException, @@ -615,6 +908,31 @@ public class TableEndpointUnitTest extends AbstractUnitTest { }); } + @Test + @WithMockUser(username = USER_1_USERNAME, authorities = {"delete-table-data"}) + public void deleteTuple_unavailable_fails() throws TableNotFoundException, RemoteUnavailableException, SQLException, + NotAllowedException, MetadataServiceException, TableMalformedException, QueryMalformedException { + final TupleDeleteDto request = TupleDeleteDto.builder() + .keys(new HashMap<>() {{ + put(COLUMN_8_1_INTERNAL_NAME, 6L); + }}) + .build(); + + /* mock */ + when(metadataServiceGateway.getTableById(DATABASE_3_ID, TABLE_8_ID)) + .thenReturn(TABLE_8_PRIVILEGED_DTO); + when(metadataServiceGateway.getAccess(DATABASE_3_ID, USER_1_ID)) + .thenReturn(DATABASE_3_USER_3_WRITE_OWN_ACCESS_DTO); + doThrow(SQLException.class) + .when(tableService) + .deleteTuple(TABLE_8_PRIVILEGED_DTO, request); + + /* test */ + assertThrows(DatabaseUnavailableException.class, () -> { + tableEndpoint.deleteRawTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_1_PRINCIPAL); + }); + } + @Test @WithMockUser(username = USER_1_USERNAME, authorities = {"delete-table-data"}) public void deleteTuple_writeOwnAccess_succeeds() throws TableNotFoundException, RemoteUnavailableException, @@ -724,6 +1042,17 @@ public class TableEndpointUnitTest extends AbstractUnitTest { }); } + @ParameterizedTest + @MethodSource("size_arguments") + @WithAnonymousUser + public void getHistory_invalidSize_fails(String name, Long size) { + + /* test */ + assertThrows(PaginationException.class, () -> { + tableEndpoint.getHistory(DATABASE_1_ID, TABLE_1_ID, size, null); + }); + } + @Test @WithMockUser(username = USER_4_USERNAME) public void getHistory_privateNoAccess_fails() throws NotAllowedException, RemoteUnavailableException, @@ -742,6 +1071,42 @@ public class TableEndpointUnitTest extends AbstractUnitTest { }); } + @Test + @WithMockUser(username = USER_2_USERNAME) + public void getHistory_private_succeeds() throws NotAllowedException, RemoteUnavailableException, SQLException, + TableNotFoundException, MetadataServiceException, DatabaseUnavailableException, PaginationException { + + /* mock */ + when(metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_1_ID)) + .thenReturn(TABLE_1_PRIVILEGED_DTO); + when(metadataServiceGateway.getAccess(DATABASE_1_ID, USER_2_ID)) + .thenReturn(DATABASE_1_USER_2_READ_ACCESS_DTO); + when(tableService.history(TABLE_1_PRIVILEGED_DTO, 10L)) + .thenReturn(List.of()); + + /* test */ + final ResponseEntity<List<TableHistoryDto>> response = tableEndpoint.getHistory(DATABASE_1_ID, TABLE_1_ID, null, USER_2_PRINCIPAL); + assertEquals(HttpStatus.OK, response.getStatusCode()); + } + + @Test + @WithAnonymousUser + public void getHistory_unavailable_succeeds() throws RemoteUnavailableException, SQLException, + TableNotFoundException, MetadataServiceException { + + /* mock */ + when(metadataServiceGateway.getTableById(DATABASE_3_ID, TABLE_8_ID)) + .thenReturn(TABLE_8_PRIVILEGED_DTO); + doThrow(SQLException.class) + .when(tableService) + .history(TABLE_8_PRIVILEGED_DTO, 100L); + + /* test */ + assertThrows(DatabaseUnavailableException.class, () -> { + tableEndpoint.getHistory(DATABASE_3_ID, TABLE_8_ID, null, null); + }); + } + @Test @WithAnonymousUser public void getHistory_tableNotFound_fails() throws TableNotFoundException, RemoteUnavailableException, @@ -775,7 +1140,32 @@ public class TableEndpointUnitTest extends AbstractUnitTest { .thenReturn(mock); /* test */ - final ResponseEntity<InputStreamResource> response = tableEndpoint.exportData(DATABASE_3_ID, TABLE_8_ID, null, null); + final ResponseEntity<InputStreamResource> response = tableEndpoint.exportDataset(DATABASE_3_ID, TABLE_8_ID, null, null); + assertEquals(HttpStatus.OK, response.getStatusCode()); + + } + + @ParameterizedTest + @WithMockUser(username = USER_2_USERNAME) + @MethodSource("anyAccess_parameters") + public void exportData_private_succeeds(String name, DatabaseAccessDto access) throws DatabaseUnavailableException, TableNotFoundException, NotAllowedException, + StorageUnavailableException, QueryMalformedException, SidecarExportException, RemoteUnavailableException, + StorageNotFoundException, SQLException, MetadataServiceException { + final ExportResourceDto mock = ExportResourceDto.builder() + .filename("deadbeef") + .resource(new InputStreamResource(InputStream.nullInputStream())) + .build(); + + /* mock */ + when(metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_1_ID)) + .thenReturn(TABLE_1_PRIVILEGED_DTO); + when(metadataServiceGateway.getAccess(DATABASE_1_ID, USER_2_ID)) + .thenReturn(access); + when(tableService.exportDataset(eq(TABLE_1_PRIVILEGED_DTO), any(Instant.class))) + .thenReturn(mock); + + /* test */ + final ResponseEntity<InputStreamResource> response = tableEndpoint.exportDataset(DATABASE_1_ID, TABLE_1_ID, null, USER_2_PRINCIPAL); assertEquals(HttpStatus.OK, response.getStatusCode()); } @@ -794,19 +1184,92 @@ public class TableEndpointUnitTest extends AbstractUnitTest { /* test */ assertThrows(NotAllowedException.class, () -> { - tableEndpoint.exportData(DATABASE_1_ID, TABLE_1_ID, null, null); + tableEndpoint.exportDataset(DATABASE_1_ID, TABLE_1_ID, null, null); }); + } + + @Test + @WithMockUser(username = USER_1_USERNAME) + public void exportData_unavailable_fails() throws TableNotFoundException, RemoteUnavailableException, + MetadataServiceException, StorageUnavailableException, SQLException, QueryMalformedException, + SidecarExportException, StorageNotFoundException { + + /* mock */ + when(metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_1_ID)) + .thenReturn(TABLE_1_PRIVILEGED_DTO); + doThrow(SQLException.class) + .when(tableService) + .exportDataset(eq(TABLE_1_PRIVILEGED_DTO), any(Instant.class)); + + /* test */ + assertThrows(DatabaseUnavailableException.class, () -> { + tableEndpoint.exportDataset(DATABASE_1_ID, TABLE_1_ID, null, USER_1_PRINCIPAL); + }); + } + + @Test + @WithMockUser(username = USER_1_USERNAME, authorities = {"system"}) + public void getSchema_succeeds() throws DatabaseUnavailableException, TableNotFoundException, + RemoteUnavailableException, SQLException, MetadataServiceException, DatabaseNotFoundException, + DatabaseMalformedException { + + /* mock */ + when(metadataServiceGateway.getDatabaseById(DATABASE_3_ID)) + .thenReturn(DATABASE_3_PRIVILEGED_DTO); + when(tableService.getSchemas(DATABASE_3_PRIVILEGED_DTO)) + .thenReturn(List.of(TABLE_8_DTO)); + + /* test */ + final ResponseEntity<List<TableDto>> response = tableEndpoint.getSchema(DATABASE_3_ID); + assertEquals(HttpStatus.OK, response.getStatusCode()); + } + + @Test + @WithAnonymousUser + public void getSchema_anonymous_succeeds() { + + /* test */ + assertThrows(AccessDeniedException.class, () -> { + tableEndpoint.getSchema(DATABASE_3_ID); + }); + } + + @Test + @WithMockUser(username = USER_4_USERNAME) + public void getSchema_noRole_succeeds() { + + /* test */ + assertThrows(AccessDeniedException.class, () -> { + tableEndpoint.getSchema(DATABASE_3_ID); + }); + } + + @Test + @WithMockUser(username = USER_1_USERNAME, authorities = {"system"}) + public void getSchema_unavailable_fails() throws TableNotFoundException, RemoteUnavailableException, SQLException, + MetadataServiceException, DatabaseNotFoundException, DatabaseMalformedException { + + /* mock */ + when(metadataServiceGateway.getDatabaseById(DATABASE_3_ID)) + .thenReturn(DATABASE_3_PRIVILEGED_DTO); + doThrow(SQLException.class) + .when(tableService) + .getSchemas(DATABASE_3_PRIVILEGED_DTO); + /* test */ + assertThrows(DatabaseUnavailableException.class, () -> { + tableEndpoint.getSchema(DATABASE_3_ID); + }); } @Test @WithMockUser(username = USER_1_USERNAME, authorities = {"insert-table-data"}) - public void importData_succeeds() throws DatabaseUnavailableException, TableNotFoundException, + public void importDataset_succeeds() throws DatabaseUnavailableException, TableNotFoundException, SidecarImportException, NotAllowedException, QueryMalformedException, RemoteUnavailableException, StorageNotFoundException, SQLException, MetadataServiceException { - final ImportCsvDto request = ImportCsvDto.builder() + final ImportDto request = ImportDto.builder() .skipLines(1L) - .lineTermination("\\n") + .lineTermination(null) .location("deadbeef") .build(); @@ -829,8 +1292,8 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_4_USERNAME) - public void importData_noRole_fails() { - final ImportCsvDto request = ImportCsvDto.builder() + public void importDataset_noRole_fails() { + final ImportDto request = ImportDto.builder() .skipLines(1L) .lineTermination("\\n") .location("deadbeef") @@ -844,9 +1307,9 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"}) - public void importData_tableNotFound_fails() throws TableNotFoundException, RemoteUnavailableException, + public void importDataset_tableNotFound_fails() throws TableNotFoundException, RemoteUnavailableException, MetadataServiceException { - final ImportCsvDto request = ImportCsvDto.builder() + final ImportDto request = ImportDto.builder() .skipLines(1L) .lineTermination("\\n") .location("deadbeef") @@ -865,9 +1328,61 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"}) - public void importData_readAccess_fails() throws TableNotFoundException, RemoteUnavailableException, + public void importDataset_unavailable_fails() throws RemoteUnavailableException, SidecarImportException, + SQLException, QueryMalformedException, StorageNotFoundException, TableNotFoundException, + MetadataServiceException, NotAllowedException { + final ImportDto request = ImportDto.builder() + .skipLines(1L) + .lineTermination("\\n") + .location("deadbeef") + .build(); + + /* mock */ + when(metadataServiceGateway.getTableById(DATABASE_3_ID, TABLE_8_ID)) + .thenReturn(TABLE_8_PRIVILEGED_DTO); + when(metadataServiceGateway.getAccess(DATABASE_3_ID, USER_3_ID)) + .thenReturn(DATABASE_3_USER_3_WRITE_ALL_ACCESS_DTO); + doThrow(SQLException.class) + .when(tableService) + .importDataset(any(PrivilegedTableDto.class), eq(request)); + + /* test */ + assertThrows(DatabaseUnavailableException.class, () -> { + tableEndpoint.importDataset(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL); + }); + } + + @Test + @WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"}) + public void importDataset_writeOwnAccess_fails() throws RemoteUnavailableException, SidecarImportException, + SQLException, QueryMalformedException, StorageNotFoundException, TableNotFoundException, + MetadataServiceException, NotAllowedException { + final ImportDto request = ImportDto.builder() + .skipLines(1L) + .lineTermination("\\n") + .location("deadbeef") + .build(); + + /* mock */ + when(metadataServiceGateway.getTableById(DATABASE_3_ID, TABLE_8_ID)) + .thenReturn(TABLE_8_PRIVILEGED_DTO); + when(metadataServiceGateway.getAccess(DATABASE_3_ID, USER_3_ID)) + .thenReturn(DATABASE_3_USER_3_WRITE_OWN_ACCESS_DTO); + doThrow(SQLException.class) + .when(tableService) + .importDataset(any(PrivilegedTableDto.class), eq(request)); + + /* test */ + assertThrows(NotAllowedException.class, () -> { + tableEndpoint.importDataset(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL); + }); + } + + @Test + @WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"}) + public void importDataset_readAccess_fails() throws TableNotFoundException, RemoteUnavailableException, NotAllowedException, MetadataServiceException { - final ImportCsvDto request = ImportCsvDto.builder() + final ImportDto request = ImportDto.builder() .skipLines(1L) .lineTermination("\\n") .location("deadbeef") @@ -887,10 +1402,10 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_1_USERNAME, authorities = {"insert-table-data"}) - public void importData_writeOwnAccess_succeeds() throws TableNotFoundException, RemoteUnavailableException, + public void importDataset_writeOwnAccess_succeeds() throws TableNotFoundException, RemoteUnavailableException, NotAllowedException, DatabaseUnavailableException, SidecarImportException, QueryMalformedException, StorageNotFoundException, MetadataServiceException { - final ImportCsvDto request = ImportCsvDto.builder() + final ImportDto request = ImportDto.builder() .skipLines(1L) .lineTermination("\\n") .location("deadbeef") @@ -908,9 +1423,9 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"}) - public void importData_writeOwnAccessForeign_fails() throws TableNotFoundException, RemoteUnavailableException, + public void importDataset_writeOwnAccessForeign_fails() throws TableNotFoundException, RemoteUnavailableException, NotAllowedException, MetadataServiceException { - final ImportCsvDto request = ImportCsvDto.builder() + final ImportDto request = ImportDto.builder() .skipLines(1L) .lineTermination("\\n") .location("deadbeef") @@ -930,10 +1445,10 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"}) - public void importData_writeAllAccessForeign_succeeds() throws TableNotFoundException, RemoteUnavailableException, + public void importDataset_writeAllAccessForeign_succeeds() throws TableNotFoundException, RemoteUnavailableException, NotAllowedException, DatabaseUnavailableException, SidecarImportException, QueryMalformedException, StorageNotFoundException, MetadataServiceException { - final ImportCsvDto request = ImportCsvDto.builder() + final ImportDto request = ImportDto.builder() .skipLines(1L) .lineTermination("\\n") .location("deadbeef") @@ -949,4 +1464,90 @@ public class TableEndpointUnitTest extends AbstractUnitTest { tableEndpoint.importDataset(DATABASE_3_ID, TABLE_8_ID, request, USER_1_PRINCIPAL); } + @Test + @WithMockUser(username = USER_2_USERNAME, authorities = {"insert-table-data"}) + public void importDataset_privateForeign_succeeds() throws TableNotFoundException, RemoteUnavailableException, + NotAllowedException, DatabaseUnavailableException, SidecarImportException, QueryMalformedException, + StorageNotFoundException, MetadataServiceException { + final ImportDto request = ImportDto.builder() + .skipLines(1L) + .lineTermination("\\n") + .location("deadbeef") + .build(); + + /* mock */ + when(metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_1_ID)) + .thenReturn(TABLE_1_PRIVILEGED_DTO); + when(metadataServiceGateway.getAccess(DATABASE_1_ID, USER_2_ID)) + .thenReturn(DATABASE_1_USER_2_WRITE_ALL_ACCESS_DTO); + + /* test */ + tableEndpoint.importDataset(DATABASE_1_ID, TABLE_1_ID, request, USER_2_PRINCIPAL); + } + + @Test + @WithMockUser(username = USER_2_USERNAME, authorities = {"insert-table-data"}) + public void importDataset_private_succeeds() throws TableNotFoundException, RemoteUnavailableException, + NotAllowedException, DatabaseUnavailableException, SidecarImportException, QueryMalformedException, + StorageNotFoundException, MetadataServiceException { + final ImportDto request = ImportDto.builder() + .skipLines(1L) + .lineTermination("\\n") + .location("deadbeef") + .build(); + + /* mock */ + when(metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_2_ID)) + .thenReturn(TABLE_2_PRIVILEGED_DTO); + when(metadataServiceGateway.getAccess(DATABASE_1_ID, USER_2_ID)) + .thenReturn(DATABASE_1_USER_2_WRITE_OWN_ACCESS_DTO); + + /* test */ + tableEndpoint.importDataset(DATABASE_1_ID, TABLE_2_ID, request, USER_2_PRINCIPAL); + } + + @Test + @WithMockUser(username = USER_2_USERNAME, authorities = {"insert-table-data"}) + public void importDataset_privateForeign_fails() throws TableNotFoundException, RemoteUnavailableException, + NotAllowedException, MetadataServiceException { + final ImportDto request = ImportDto.builder() + .skipLines(1L) + .lineTermination("\\n") + .location("deadbeef") + .build(); + + /* mock */ + when(metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_1_ID)) + .thenReturn(TABLE_1_PRIVILEGED_DTO); + when(metadataServiceGateway.getAccess(DATABASE_1_ID, USER_2_ID)) + .thenReturn(DATABASE_1_USER_2_WRITE_OWN_ACCESS_DTO); + + /* test */ + assertThrows(NotAllowedException.class, () -> { + tableEndpoint.importDataset(DATABASE_1_ID, TABLE_1_ID, request, USER_2_PRINCIPAL); + }); + } + + @Test + @WithMockUser(username = USER_2_USERNAME, authorities = {"insert-table-data"}) + public void importDataset_privateReadAccess_fails() throws TableNotFoundException, RemoteUnavailableException, + NotAllowedException, MetadataServiceException { + final ImportDto request = ImportDto.builder() + .skipLines(1L) + .lineTermination("\\n") + .location("deadbeef") + .build(); + + /* mock */ + when(metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_2_ID)) + .thenReturn(TABLE_2_PRIVILEGED_DTO); + when(metadataServiceGateway.getAccess(DATABASE_1_ID, USER_2_ID)) + .thenReturn(DATABASE_1_USER_2_READ_ACCESS_DTO); + + /* test */ + assertThrows(NotAllowedException.class, () -> { + tableEndpoint.importDataset(DATABASE_1_ID, TABLE_2_ID, request, USER_2_PRINCIPAL); + }); + } + } diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/ViewEndpointUnitTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/ViewEndpointUnitTest.java index 543b4a5cf299d48a8a4594f95e8586752d4278cc..fd1030c17bee1f169c01d33da8af86f339feecbe 100644 --- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/ViewEndpointUnitTest.java +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/ViewEndpointUnitTest.java @@ -17,11 +17,14 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.test.context.support.WithAnonymousUser; import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.context.junit.jupiter.SpringExtension; import java.sql.SQLException; import java.time.Instant; +import java.util.List; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; @@ -64,6 +67,24 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { assertEquals(HttpStatus.CREATED, response.getStatusCode()); } + @Test + @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"}) + public void create_unavailable_fails() throws DatabaseNotFoundException, RemoteUnavailableException, SQLException, + ViewMalformedException, MetadataServiceException { + + /* mock */ + when(metadataServiceGateway.getDatabaseById(DATABASE_1_ID)) + .thenReturn(DATABASE_1_PRIVILEGED_DTO); + doThrow(SQLException.class) + .when(viewService) + .create(DATABASE_1_PRIVILEGED_DTO, VIEW_1_CREATE_DTO); + + /* test */ + assertThrows(DatabaseUnavailableException.class, () -> { + viewEndpoint.create(DATABASE_1_ID, VIEW_1_CREATE_DTO); + }); + } + @Test @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME) public void create_noRole_fails() throws DatabaseNotFoundException, RemoteUnavailableException, ViewMalformedException, @@ -97,6 +118,76 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { }); } + @Test + @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"}) + public void getSchema_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException, SQLException, + DatabaseMalformedException, DatabaseUnavailableException, ViewNotFoundException, MetadataServiceException { + + /* mock */ + when(metadataServiceGateway.getDatabaseById(DATABASE_1_ID)) + .thenReturn(DATABASE_1_PRIVILEGED_DTO); + when(viewService.getSchemas(DATABASE_1_PRIVILEGED_DTO)) + .thenReturn(List.of(VIEW_1_DTO, VIEW_2_DTO, VIEW_3_DTO)); + + /* test */ + final ResponseEntity<List<ViewDto>> response = viewEndpoint.getSchema(DATABASE_1_ID); + assertEquals(HttpStatus.OK, response.getStatusCode()); + } + + @Test + @WithAnonymousUser + public void getSchema_anonymous_fails() { + + /* test */ + assertThrows(org.springframework.security.access.AccessDeniedException.class, () -> { + viewEndpoint.getSchema(DATABASE_1_ID); + }); + } + + @Test + @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"}) + public void getSchema_databaseNotFound_fails() throws DatabaseNotFoundException, RemoteUnavailableException, + MetadataServiceException { + + /* mock */ + doThrow(DatabaseNotFoundException.class) + .when(metadataServiceGateway) + .getDatabaseById(DATABASE_1_ID); + + /* test */ + assertThrows(DatabaseNotFoundException.class, () -> { + viewEndpoint.getSchema(DATABASE_1_ID); + }); + } + + @Test + @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"}) + public void getSchema_unavailable_fails() throws DatabaseNotFoundException, RemoteUnavailableException, + SQLException, DatabaseMalformedException, ViewNotFoundException, MetadataServiceException { + + /* mock */ + when(metadataServiceGateway.getDatabaseById(DATABASE_1_ID)) + .thenReturn(DATABASE_1_PRIVILEGED_DTO); + doThrow(SQLException.class) + .when(viewService) + .getSchemas(DATABASE_1_PRIVILEGED_DTO); + + /* test */ + assertThrows(DatabaseUnavailableException.class, () -> { + viewEndpoint.getSchema(DATABASE_1_ID); + }); + } + + @Test + @WithAnonymousUser + public void delete_anonymous_fails() { + + /* test */ + assertThrows(org.springframework.security.access.AccessDeniedException.class, () -> { + viewEndpoint.delete(DATABASE_1_ID, VIEW_1_ID); + }); + } + @Test @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"}) public void delete_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException, ViewMalformedException, @@ -114,6 +205,24 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { assertEquals(HttpStatus.ACCEPTED, response.getStatusCode()); } + @Test + @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"}) + public void delete_unavailable_fails() throws RemoteUnavailableException, ViewMalformedException, SQLException, + MetadataServiceException, ViewNotFoundException { + + /* mock */ + when(metadataServiceGateway.getViewById(DATABASE_1_ID, VIEW_1_ID)) + .thenReturn(VIEW_1_PRIVILEGED_DTO); + doThrow(SQLException.class) + .when(viewService) + .delete(VIEW_1_PRIVILEGED_DTO); + + /* test */ + assertThrows(DatabaseUnavailableException.class, () -> { + viewEndpoint.delete(DATABASE_1_ID, VIEW_1_ID); + }); + } + @Test @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME) public void delete_noRole_fails() throws DatabaseNotFoundException, RemoteUnavailableException, ViewMalformedException, @@ -150,7 +259,7 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_1_USERNAME, authorities = {"view-database-view-data"}) - public void getData_succeeds() throws RemoteUnavailableException, ViewNotFoundException, ViewMalformedException, + public void getData_private_succeeds() throws RemoteUnavailableException, ViewNotFoundException, ViewMalformedException, SQLException, DatabaseUnavailableException, QueryMalformedException, PaginationException, NotAllowedException, MetadataServiceException { @@ -167,40 +276,79 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { /* test */ final ResponseEntity<QueryResultDto> response = viewEndpoint.getData(DATABASE_1_ID, VIEW_1_ID, null, null, null, httpServletRequest, USER_1_PRINCIPAL); assertEquals(HttpStatus.OK, response.getStatusCode()); - assertNotNull(response.getHeaders().get("Access-Control-Expose-Headers")); - assertEquals(1, response.getHeaders().get("Access-Control-Expose-Headers").size()); - assertEquals("X-Count", response.getHeaders().get("Access-Control-Expose-Headers").get(0)); assertNotNull(response.getBody()); } @Test @WithMockUser(username = USER_1_USERNAME, authorities = {"view-database-view-data"}) - public void getData_onlyHead_succeeds() throws RemoteUnavailableException, ViewNotFoundException, + public void getData_privateHead_succeeds() throws RemoteUnavailableException, ViewNotFoundException, ViewMalformedException, SQLException, DatabaseUnavailableException, QueryMalformedException, PaginationException, NotAllowedException, MetadataServiceException { /* mock */ - when(metadataServiceGateway.getViewById(DATABASE_1_ID, VIEW_1_ID)) - .thenReturn(VIEW_1_PRIVILEGED_DTO); + when(metadataServiceGateway.getViewById(DATABASE_1_ID, VIEW_3_ID)) + .thenReturn(VIEW_3_PRIVILEGED_DTO); when(metadataServiceGateway.getAccess(DATABASE_1_ID, USER_1_ID)) .thenReturn(DATABASE_1_USER_1_READ_ACCESS_DTO); when(httpServletRequest.getMethod()) .thenReturn("HEAD"); - when(viewService.count(eq(VIEW_1_PRIVILEGED_DTO), any(Instant.class))) - .thenReturn(VIEW_1_DATA_COUNT); + when(viewService.count(eq(VIEW_3_PRIVILEGED_DTO), any(Instant.class))) + .thenReturn(VIEW_3_DATA_COUNT); /* test */ - final ResponseEntity<QueryResultDto> response = viewEndpoint.getData(DATABASE_1_ID, VIEW_1_ID, null, null, null, httpServletRequest, USER_1_PRINCIPAL); + final ResponseEntity<QueryResultDto> response = viewEndpoint.getData(DATABASE_1_ID, VIEW_3_ID, null, null, null, httpServletRequest, USER_1_PRINCIPAL); assertEquals(HttpStatus.OK, response.getStatusCode()); assertNotNull(response.getHeaders().get("X-Count")); assertEquals(1, response.getHeaders().get("X-Count").size()); - assertEquals(VIEW_1_DATA_COUNT, Long.parseLong(response.getHeaders().get("X-Count").get(0))); + assertEquals(VIEW_3_DATA_COUNT, Long.parseLong(response.getHeaders().get("X-Count").get(0))); assertNotNull(response.getHeaders().get("Access-Control-Expose-Headers")); assertEquals(1, response.getHeaders().get("Access-Control-Expose-Headers").size()); assertEquals("X-Count", response.getHeaders().get("Access-Control-Expose-Headers").get(0)); assertNull(response.getBody()); } + @Test + @WithMockUser(username = USER_1_USERNAME, authorities = {"view-database-view-data"}) + public void getData_unavailable_fails() throws RemoteUnavailableException, ViewNotFoundException, SQLException, + ViewMalformedException, NotAllowedException, MetadataServiceException { + + /* mock */ + when(metadataServiceGateway.getViewById(DATABASE_1_ID, VIEW_1_ID)) + .thenReturn(VIEW_1_PRIVILEGED_DTO); + when(metadataServiceGateway.getAccess(DATABASE_1_ID, USER_1_ID)) + .thenReturn(DATABASE_1_USER_1_READ_ACCESS_DTO); + when(httpServletRequest.getMethod()) + .thenReturn("GET"); + doThrow(SQLException.class) + .when(viewService) + .data(eq(VIEW_1_PRIVILEGED_DTO), any(Instant.class), eq(0L), eq(10L)); + + /* test */ + assertThrows(DatabaseUnavailableException.class, () -> { + viewEndpoint.getData(DATABASE_1_ID, VIEW_1_ID, null, null, null, httpServletRequest, USER_1_PRINCIPAL); + }); + } + + @Test + @WithMockUser(username = USER_1_USERNAME, authorities = {"view-database-view-data"}) + public void getData_privateNoAccess_succeeds() throws RemoteUnavailableException, ViewNotFoundException, + NotAllowedException, MetadataServiceException { + + /* mock */ + when(metadataServiceGateway.getViewById(DATABASE_1_ID, VIEW_3_ID)) + .thenReturn(VIEW_3_PRIVILEGED_DTO); + when(httpServletRequest.getMethod()) + .thenReturn("GET"); + doThrow(NotAllowedException.class) + .when(metadataServiceGateway) + .getAccess(DATABASE_1_ID, USER_1_ID); + + /* test */ + assertThrows(NotAllowedException.class, () -> { + viewEndpoint.getData(DATABASE_1_ID, VIEW_3_ID, null, null, null, httpServletRequest, USER_1_PRINCIPAL); + }); + } + @Test @WithMockUser(username = USER_1_USERNAME, authorities = {"view-database-view-data"}) public void getData_viewNotFound_fails() throws RemoteUnavailableException, ViewNotFoundException, diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/gateway/MetadataServiceGatewayUnitTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/gateway/MetadataServiceGatewayUnitTest.java index c224af4cb28604c2554da1942a782932db8d7390..44b01b1e9e2919721e446d7e183fbbcb739ea813 100644 --- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/gateway/MetadataServiceGatewayUnitTest.java +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/gateway/MetadataServiceGatewayUnitTest.java @@ -175,8 +175,12 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest { MetadataServiceException { /* mock */ + final HttpHeaders headers = new HttpHeaders(); + headers.set("X-Username", CONTAINER_1_PRIVILEGED_USERNAME); + headers.set("X-Password", CONTAINER_1_PRIVILEGED_PASSWORD); when(restTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(PrivilegedDatabaseDto[].class))) .thenReturn(ResponseEntity.status(HttpStatus.OK) + .headers(headers) .body(new PrivilegedDatabaseDto[]{DATABASE_1_PRIVILEGED_DTO})); /* test */ @@ -221,7 +225,7 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest { .build()); /* test */ - assertThrows(MetadataServiceException.class, () -> { + assertThrows(DatabaseNotFoundException.class, () -> { metadataServiceGateway.getDatabaseByInternalName(DATABASE_1_INTERNALNAME); }); } diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/handlers/ApiExceptionHandlerTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/handlers/ApiExceptionHandlerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..ce56ce82da975f8f41d7233b0a017143044457ed --- /dev/null +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/handlers/ApiExceptionHandlerTest.java @@ -0,0 +1,1232 @@ +package at.tuwien.handlers; + +import at.tuwien.api.error.ApiErrorDto; +import at.tuwien.exception.*; +import at.tuwien.test.AbstractUnitTest; +import lombok.extern.log4j.Log4j2; +import org.junit.jupiter.api.Assertions; +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.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.web.bind.annotation.ResponseStatus; + +import java.io.IOException; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; + +import static at.tuwien.test.utils.EndpointUtils.getErrorCodes; +import static at.tuwien.test.utils.EndpointUtils.getExceptions; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +@Log4j2 +@ExtendWith(SpringExtension.class) +@SpringBootTest +public class ApiExceptionHandlerTest extends AbstractUnitTest { + + @Autowired + private ApiExceptionHandler apiExceptionHandler; + + @Test + public void handle_succeeds() throws ClassNotFoundException, IOException { + final List<Method> handlers = Arrays.asList(ApiExceptionHandler.class.getMethods()); + final List<String> errorCodes = getErrorCodes(); + + /* test */ + for (Class<?> exception : getExceptions()) { + final Optional<Method> optional = handlers.stream().filter(h -> Arrays.asList(h.getParameterTypes()).contains(exception)).findFirst(); + if (optional.isEmpty()) { + Assertions.fail("Exception " + exception.getName() + " does not have a corresponding handle method in the endpoint"); + } + final Method method = optional.get(); + /* exception */ + assertNotNull(exception.getDeclaredAnnotation(ResponseStatus.class).code()); + Assertions.assertNotEquals(exception.getDeclaredAnnotation(ResponseStatus.class).code(), HttpStatus.INTERNAL_SERVER_ERROR); + assertNotNull(exception.getDeclaredAnnotation(ResponseStatus.class).reason(), "Exception " + exception.getName() + " does not provide a reason code"); + Assertions.assertTrue(errorCodes.contains(exception.getDeclaredAnnotation(ResponseStatus.class).reason()), "Exception code " + exception.getDeclaredAnnotation(ResponseStatus.class).reason() + " does have a reason code mapped in localized ui error messages"); + /* handler method */ + Assertions.assertEquals(method.getDeclaredAnnotation(ResponseStatus.class).code(), exception.getDeclaredAnnotation(ResponseStatus.class).code()); + } + } + + @Test + public void generic_handle_succeeds() { + + /* test */ + apiExceptionHandler.generic_handle(DatabaseNotFoundException.class, "msg"); + } + + @Test + public void handle_AccessDeniedException_succeeds() { + final AccessDeniedException request = new AccessDeniedException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + Assertions.assertNotEquals(response.getStatusCode(), HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(HttpStatus.UNAUTHORIZED, response.getStatusCode()); + assertNotNull(response.getBody()); + assertEquals("error.access.denied", response.getBody().getCode()); + assertEquals("msg", response.getBody().getMessage()); + } + + + @Test + public void handle_AccessNotFoundException_succeeds() { + final AccessNotFoundException request = new AccessNotFoundException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code()); + final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code(); + Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(httpStatus, response.getStatusCode()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getCode()); + assertEquals(httpStatus, response.getBody().getStatus()); + assertEquals("msg", response.getBody().getMessage()); + } + + + @Test + public void handle_AccountNotSetupException_succeeds() { + final AccountNotSetupException request = new AccountNotSetupException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code()); + final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code(); + Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(httpStatus, response.getStatusCode()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getCode()); + assertEquals(httpStatus, response.getBody().getStatus()); + assertEquals("msg", response.getBody().getMessage()); + } + + + @Test + public void handle_AuthServiceConnectionException_succeeds() { + final AuthServiceConnectionException request = new AuthServiceConnectionException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code()); + final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code(); + Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(httpStatus, response.getStatusCode()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getCode()); + assertEquals(httpStatus, response.getBody().getStatus()); + assertEquals("msg", response.getBody().getMessage()); + } + + + @Test + public void handle_AuthServiceException_succeeds() { + final AuthServiceException request = new AuthServiceException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code()); + final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code(); + Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(httpStatus, response.getStatusCode()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getCode()); + assertEquals(httpStatus, response.getBody().getStatus()); + assertEquals("msg", response.getBody().getMessage()); + } + + + @Test + public void handle_BrokerServiceConnectionException_succeeds() { + final BrokerServiceConnectionException request = new BrokerServiceConnectionException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code()); + final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code(); + Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(httpStatus, response.getStatusCode()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getCode()); + assertEquals(httpStatus, response.getBody().getStatus()); + assertEquals("msg", response.getBody().getMessage()); + } + + + @Test + public void handle_BrokerServiceException_succeeds() { + final BrokerServiceException request = new BrokerServiceException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code()); + final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code(); + Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(httpStatus, response.getStatusCode()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getCode()); + assertEquals(httpStatus, response.getBody().getStatus()); + assertEquals("msg", response.getBody().getMessage()); + } + + + @Test + public void handle_ConceptNotFoundException_succeeds() { + final ConceptNotFoundException request = new ConceptNotFoundException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code()); + final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code(); + Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(httpStatus, response.getStatusCode()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getCode()); + assertEquals(httpStatus, response.getBody().getStatus()); + assertEquals("msg", response.getBody().getMessage()); + } + + + @Test + public void handle_ContainerAlreadyExistsException_succeeds() { + final ContainerAlreadyExistsException request = new ContainerAlreadyExistsException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code()); + final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code(); + Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(httpStatus, response.getStatusCode()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getCode()); + assertEquals(httpStatus, response.getBody().getStatus()); + assertEquals("msg", response.getBody().getMessage()); + } + + + @Test + public void handle_ContainerNotFoundException_succeeds() { + final ContainerNotFoundException request = new ContainerNotFoundException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code()); + final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code(); + Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(httpStatus, response.getStatusCode()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getCode()); + assertEquals(httpStatus, response.getBody().getStatus()); + assertEquals("msg", response.getBody().getMessage()); + } + + + @Test + public void handle_CredentialsInvalidException_succeeds() { + final CredentialsInvalidException request = new CredentialsInvalidException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code()); + final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code(); + Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(httpStatus, response.getStatusCode()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getCode()); + assertEquals(httpStatus, response.getBody().getStatus()); + assertEquals("msg", response.getBody().getMessage()); + } + + + @Test + public void handle_DatabaseMalformedException_succeeds() { + final DatabaseMalformedException request = new DatabaseMalformedException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code()); + final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code(); + Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(httpStatus, response.getStatusCode()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getCode()); + assertEquals(httpStatus, response.getBody().getStatus()); + assertEquals("msg", response.getBody().getMessage()); + } + + + @Test + public void handle_DatabaseNotFoundException_succeeds() { + final DatabaseNotFoundException request = new DatabaseNotFoundException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code()); + final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code(); + Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(httpStatus, response.getStatusCode()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getCode()); + assertEquals(httpStatus, response.getBody().getStatus()); + assertEquals("msg", response.getBody().getMessage()); + } + + + @Test + public void handle_DatabaseUnavailableException_succeeds() { + final DatabaseUnavailableException request = new DatabaseUnavailableException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code()); + final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code(); + Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(httpStatus, response.getStatusCode()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getCode()); + assertEquals(httpStatus, response.getBody().getStatus()); + assertEquals("msg", response.getBody().getMessage()); + } + + + @Test + public void handle_DoiNotFoundException_succeeds() { + final DoiNotFoundException request = new DoiNotFoundException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code()); + final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code(); + Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(httpStatus, response.getStatusCode()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getCode()); + assertEquals(httpStatus, response.getBody().getStatus()); + assertEquals("msg", response.getBody().getMessage()); + } + + + @Test + public void handle_EmailExistsException_succeeds() { + final EmailExistsException request = new EmailExistsException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code()); + final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code(); + Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(httpStatus, response.getStatusCode()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getCode()); + assertEquals(httpStatus, response.getBody().getStatus()); + assertEquals("msg", response.getBody().getMessage()); + } + + + @Test + public void handle_ExchangeNotFoundException_succeeds() { + final ExchangeNotFoundException request = new ExchangeNotFoundException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code()); + final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code(); + Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(httpStatus, response.getStatusCode()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getCode()); + assertEquals(httpStatus, response.getBody().getStatus()); + assertEquals("msg", response.getBody().getMessage()); + } + + + @Test + public void handle_ExternalServiceException_succeeds() { + final ExternalServiceException request = new ExternalServiceException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code()); + final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code(); + Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(httpStatus, response.getStatusCode()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getCode()); + assertEquals(httpStatus, response.getBody().getStatus()); + assertEquals("msg", response.getBody().getMessage()); + } + + + @Test + public void handle_FilterBadRequestException_succeeds() { + final FilterBadRequestException request = new FilterBadRequestException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code()); + final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code(); + Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(httpStatus, response.getStatusCode()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getCode()); + assertEquals(httpStatus, response.getBody().getStatus()); + assertEquals("msg", response.getBody().getMessage()); + } + + + @Test + public void handle_FormatNotAvailableException_succeeds() { + final FormatNotAvailableException request = new FormatNotAvailableException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code()); + final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code(); + Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(httpStatus, response.getStatusCode()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getCode()); + assertEquals(httpStatus, response.getBody().getStatus()); + assertEquals("msg", response.getBody().getMessage()); + } + + + @Test + public void handle_IdentifierNotFoundException_succeeds() { + final IdentifierNotFoundException request = new IdentifierNotFoundException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code()); + final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code(); + Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(httpStatus, response.getStatusCode()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getCode()); + assertEquals(httpStatus, response.getBody().getStatus()); + assertEquals("msg", response.getBody().getMessage()); + } + + + @Test + public void handle_IdentifierNotSupportedException_succeeds() { + final IdentifierNotSupportedException request = new IdentifierNotSupportedException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code()); + final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code(); + Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(httpStatus, response.getStatusCode()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getCode()); + assertEquals(httpStatus, response.getBody().getStatus()); + assertEquals("msg", response.getBody().getMessage()); + } + + + @Test + public void handle_ImageAlreadyExistsException_succeeds() { + final ImageAlreadyExistsException request = new ImageAlreadyExistsException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code()); + final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code(); + Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(httpStatus, response.getStatusCode()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getCode()); + assertEquals(httpStatus, response.getBody().getStatus()); + assertEquals("msg", response.getBody().getMessage()); + } + + + @Test + public void handle_ImageInvalidException_succeeds() { + final ImageInvalidException request = new ImageInvalidException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code()); + final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code(); + Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(httpStatus, response.getStatusCode()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getCode()); + assertEquals(httpStatus, response.getBody().getStatus()); + assertEquals("msg", response.getBody().getMessage()); + } + + + @Test + public void handle_ImageNotFoundException_succeeds() { + final ImageNotFoundException request = new ImageNotFoundException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code()); + final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code(); + Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(httpStatus, response.getStatusCode()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getCode()); + assertEquals(httpStatus, response.getBody().getStatus()); + assertEquals("msg", response.getBody().getMessage()); + } + + + @Test + public void handle_LicenseNotFoundException_succeeds() { + final LicenseNotFoundException request = new LicenseNotFoundException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code()); + final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code(); + Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(httpStatus, response.getStatusCode()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getCode()); + assertEquals(httpStatus, response.getBody().getStatus()); + assertEquals("msg", response.getBody().getMessage()); + } + + + @Test + public void handle_MalformedException_succeeds() { + final MalformedException request = new MalformedException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code()); + final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code(); + Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(httpStatus, response.getStatusCode()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getCode()); + assertEquals(httpStatus, response.getBody().getStatus()); + assertEquals("msg", response.getBody().getMessage()); + } + + + @Test + public void handle_MessageNotFoundException_succeeds() { + final MessageNotFoundException request = new MessageNotFoundException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code()); + final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code(); + Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(httpStatus, response.getStatusCode()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getCode()); + assertEquals(httpStatus, response.getBody().getStatus()); + assertEquals("msg", response.getBody().getMessage()); + } + + + @Test + public void handle_MetadataServiceConnectionException_succeeds() { + final MetadataServiceConnectionException request = new MetadataServiceConnectionException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code()); + final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code(); + Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(httpStatus, response.getStatusCode()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getCode()); + assertEquals(httpStatus, response.getBody().getStatus()); + assertEquals("msg", response.getBody().getMessage()); + } + + + @Test + public void handle_MetadataServiceException_succeeds() { + final MetadataServiceException request = new MetadataServiceException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code()); + final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code(); + Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(httpStatus, response.getStatusCode()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getCode()); + assertEquals(httpStatus, response.getBody().getStatus()); + assertEquals("msg", response.getBody().getMessage()); + } + + + @Test + public void handle_NotAllowedException_succeeds() { + final NotAllowedException request = new NotAllowedException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code()); + final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code(); + Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(httpStatus, response.getStatusCode()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getCode()); + assertEquals(httpStatus, response.getBody().getStatus()); + assertEquals("msg", response.getBody().getMessage()); + } + + + @Test + public void handle_OntologyNotFoundException_succeeds() { + final OntologyNotFoundException request = new OntologyNotFoundException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code()); + final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code(); + Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(httpStatus, response.getStatusCode()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getCode()); + assertEquals(httpStatus, response.getBody().getStatus()); + assertEquals("msg", response.getBody().getMessage()); + } + + + @Test + public void handle_OrcidNotFoundException_succeeds() { + final OrcidNotFoundException request = new OrcidNotFoundException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code()); + final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code(); + Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(httpStatus, response.getStatusCode()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getCode()); + assertEquals(httpStatus, response.getBody().getStatus()); + assertEquals("msg", response.getBody().getMessage()); + } + + + @Test + public void handle_PaginationException_succeeds() { + final PaginationException request = new PaginationException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code()); + final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code(); + Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(httpStatus, response.getStatusCode()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getCode()); + assertEquals(httpStatus, response.getBody().getStatus()); + assertEquals("msg", response.getBody().getMessage()); + } + + + @Test + public void handle_QueryMalformedException_succeeds() { + final QueryMalformedException request = new QueryMalformedException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code()); + final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code(); + Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(httpStatus, response.getStatusCode()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getCode()); + assertEquals(httpStatus, response.getBody().getStatus()); + assertEquals("msg", response.getBody().getMessage()); + } + + + @Test + public void handle_QueryNotFoundException_succeeds() { + final QueryNotFoundException request = new QueryNotFoundException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code()); + final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code(); + Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(httpStatus, response.getStatusCode()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getCode()); + assertEquals(httpStatus, response.getBody().getStatus()); + assertEquals("msg", response.getBody().getMessage()); + } + + + @Test + public void handle_QueryNotSupportedException_succeeds() { + final QueryNotSupportedException request = new QueryNotSupportedException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code()); + final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code(); + Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(httpStatus, response.getStatusCode()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getCode()); + assertEquals(httpStatus, response.getBody().getStatus()); + assertEquals("msg", response.getBody().getMessage()); + } + + + @Test + public void handle_QueueNotFoundException_succeeds() { + final QueueNotFoundException request = new QueueNotFoundException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code()); + final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code(); + Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(httpStatus, response.getStatusCode()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getCode()); + assertEquals(httpStatus, response.getBody().getStatus()); + assertEquals("msg", response.getBody().getMessage()); + } + + + @Test + public void handle_QueryStoreCreateException_succeeds() { + final QueryStoreCreateException request = new QueryStoreCreateException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code()); + final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code(); + Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(httpStatus, response.getStatusCode()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getCode()); + assertEquals(httpStatus, response.getBody().getStatus()); + assertEquals("msg", response.getBody().getMessage()); + } + + + @Test + public void handle_QueryStoreGCException_succeeds() { + final QueryStoreGCException request = new QueryStoreGCException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code()); + final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code(); + Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(httpStatus, response.getStatusCode()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getCode()); + assertEquals(httpStatus, response.getBody().getStatus()); + assertEquals("msg", response.getBody().getMessage()); + } + + + @Test + public void handle_QueryStoreInsertException_succeeds() { + final QueryStoreInsertException request = new QueryStoreInsertException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code()); + final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code(); + Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(httpStatus, response.getStatusCode()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getCode()); + assertEquals(httpStatus, response.getBody().getStatus()); + assertEquals("msg", response.getBody().getMessage()); + } + + + @Test + public void handle_QueryStorePersistException_succeeds() { + final QueryStorePersistException request = new QueryStorePersistException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code()); + final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code(); + Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(httpStatus, response.getStatusCode()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getCode()); + assertEquals(httpStatus, response.getBody().getStatus()); + assertEquals("msg", response.getBody().getMessage()); + } + + + @Test + public void handle_RemoteUnavailableException_succeeds() { + final RemoteUnavailableException request = new RemoteUnavailableException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code()); + final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code(); + Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(httpStatus, response.getStatusCode()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getCode()); + assertEquals(httpStatus, response.getBody().getStatus()); + assertEquals("msg", response.getBody().getMessage()); + } + + + @Test + public void handle_RorNotFoundException_succeeds() { + final RorNotFoundException request = new RorNotFoundException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code()); + final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code(); + Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(httpStatus, response.getStatusCode()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getCode()); + assertEquals(httpStatus, response.getBody().getStatus()); + assertEquals("msg", response.getBody().getMessage()); + } + + + @Test + public void handle_SearchServiceConnectionException_succeeds() { + final SearchServiceConnectionException request = new SearchServiceConnectionException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code()); + final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code(); + Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(httpStatus, response.getStatusCode()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getCode()); + assertEquals(httpStatus, response.getBody().getStatus()); + assertEquals("msg", response.getBody().getMessage()); + } + + + @Test + public void handle_SearchServiceException_succeeds() { + final SearchServiceException request = new SearchServiceException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code()); + final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code(); + Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(httpStatus, response.getStatusCode()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getCode()); + assertEquals(httpStatus, response.getBody().getStatus()); + assertEquals("msg", response.getBody().getMessage()); + } + + + @Test + public void handle_SemanticEntityNotFoundException_succeeds() { + final SemanticEntityNotFoundException request = new SemanticEntityNotFoundException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code()); + final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code(); + Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(httpStatus, response.getStatusCode()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getCode()); + assertEquals(httpStatus, response.getBody().getStatus()); + assertEquals("msg", response.getBody().getMessage()); + } + + + @Test + public void handle_DataServiceConnectionException_succeeds() { + final DataServiceConnectionException request = new DataServiceConnectionException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code()); + final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code(); + Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(httpStatus, response.getStatusCode()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getCode()); + assertEquals(httpStatus, response.getBody().getStatus()); + assertEquals("msg", response.getBody().getMessage()); + } + + + @Test + public void handle_DataServiceException_succeeds() { + final DataServiceException request = new DataServiceException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code()); + final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code(); + Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(httpStatus, response.getStatusCode()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getCode()); + assertEquals(httpStatus, response.getBody().getStatus()); + assertEquals("msg", response.getBody().getMessage()); + } + + + @Test + public void handle_SidecarExportException_succeeds() { + final SidecarExportException request = new SidecarExportException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code()); + final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code(); + Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(httpStatus, response.getStatusCode()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getCode()); + assertEquals(httpStatus, response.getBody().getStatus()); + assertEquals("msg", response.getBody().getMessage()); + } + + + @Test + public void handle_SidecarImportException_succeeds() { + final SidecarImportException request = new SidecarImportException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code()); + final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code(); + Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(httpStatus, response.getStatusCode()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getCode()); + assertEquals(httpStatus, response.getBody().getStatus()); + assertEquals("msg", response.getBody().getMessage()); + } + + + @Test + public void handle_SortException_succeeds() { + final SortException request = new SortException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code()); + final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code(); + Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(httpStatus, response.getStatusCode()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getCode()); + assertEquals(httpStatus, response.getBody().getStatus()); + assertEquals("msg", response.getBody().getMessage()); + } + + + @Test + public void handle_StorageNotFoundException_succeeds() { + final StorageNotFoundException request = new StorageNotFoundException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code()); + final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code(); + Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(httpStatus, response.getStatusCode()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getCode()); + assertEquals(httpStatus, response.getBody().getStatus()); + assertEquals("msg", response.getBody().getMessage()); + } + + + @Test + public void handle_StorageUnavailableException_succeeds() { + final StorageUnavailableException request = new StorageUnavailableException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code()); + final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code(); + Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(httpStatus, response.getStatusCode()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getCode()); + assertEquals(httpStatus, response.getBody().getStatus()); + assertEquals("msg", response.getBody().getMessage()); + } + + + @Test + public void handle_TableExistsException_succeeds() { + final TableExistsException request = new TableExistsException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code()); + final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code(); + Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(httpStatus, response.getStatusCode()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getCode()); + assertEquals(httpStatus, response.getBody().getStatus()); + assertEquals("msg", response.getBody().getMessage()); + } + + + @Test + public void handle_TableMalformedException_succeeds() { + final TableMalformedException request = new TableMalformedException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code()); + final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code(); + Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(httpStatus, response.getStatusCode()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getCode()); + assertEquals(httpStatus, response.getBody().getStatus()); + assertEquals("msg", response.getBody().getMessage()); + } + + + @Test + public void handle_TableSchemaException_succeeds() { + final TableSchemaException request = new TableSchemaException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code()); + final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code(); + Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(httpStatus, response.getStatusCode()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getCode()); + assertEquals(httpStatus, response.getBody().getStatus()); + assertEquals("msg", response.getBody().getMessage()); + } + + + @Test + public void handle_TableNotFoundException_succeeds() { + final TableNotFoundException request = new TableNotFoundException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code()); + final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code(); + Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(httpStatus, response.getStatusCode()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getCode()); + assertEquals(httpStatus, response.getBody().getStatus()); + assertEquals("msg", response.getBody().getMessage()); + } + + + @Test + public void handle_UnitNotFoundException_succeeds() { + final UnitNotFoundException request = new UnitNotFoundException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code()); + final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code(); + Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(httpStatus, response.getStatusCode()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getCode()); + assertEquals(httpStatus, response.getBody().getStatus()); + assertEquals("msg", response.getBody().getMessage()); + } + + + @Test + public void handle_UriMalformedException_succeeds() { + final UriMalformedException request = new UriMalformedException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code()); + final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code(); + Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(httpStatus, response.getStatusCode()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getCode()); + assertEquals(httpStatus, response.getBody().getStatus()); + assertEquals("msg", response.getBody().getMessage()); + } + + + @Test + public void handle_UserExistsException_succeeds() { + final UserExistsException request = new UserExistsException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code()); + final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code(); + Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(httpStatus, response.getStatusCode()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getCode()); + assertEquals(httpStatus, response.getBody().getStatus()); + assertEquals("msg", response.getBody().getMessage()); + } + + + @Test + public void handle_UserNotFoundException_succeeds() { + final UserNotFoundException request = new UserNotFoundException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code()); + final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code(); + Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(httpStatus, response.getStatusCode()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getCode()); + assertEquals(httpStatus, response.getBody().getStatus()); + assertEquals("msg", response.getBody().getMessage()); + } + + + @Test + public void handle_ViewMalformedException_succeeds() { + final ViewMalformedException request = new ViewMalformedException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code()); + final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code(); + Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(httpStatus, response.getStatusCode()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getCode()); + assertEquals(httpStatus, response.getBody().getStatus()); + assertEquals("msg", response.getBody().getMessage()); + } + + + @Test + public void handle_ViewNotFoundException_succeeds() { + final ViewNotFoundException request = new ViewNotFoundException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code()); + final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code(); + Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(httpStatus, response.getStatusCode()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getCode()); + assertEquals(httpStatus, response.getBody().getStatus()); + assertEquals("msg", response.getBody().getMessage()); + } + + + @Test + public void handle_ViewSchemaException_succeeds() { + final ViewSchemaException request = new ViewSchemaException("msg"); + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(request); + assertNotNull(response); + assertNotNull(request.getClass().getDeclaredAnnotation(ResponseStatus.class).code()); + final HttpStatus httpStatus = request.getClass().getDeclaredAnnotation(ResponseStatus.class).code(); + Assertions.assertNotEquals(httpStatus, HttpStatus.INTERNAL_SERVER_ERROR); + assertEquals(httpStatus, response.getStatusCode()); + assertNotNull(response.getBody()); + assertNotNull(response.getBody().getCode()); + assertEquals(httpStatus, response.getBody().getStatus()); + assertEquals("msg", response.getBody().getMessage()); + } + +} diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/mvc/PrometheusEndpointMvcTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/mvc/PrometheusEndpointMvcTest.java index 5898372633b0d63c5b256f6b567f8a8869583ab7..f4bd429a9039ab2f2fb36c4fc2fce653ceda8054 100644 --- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/mvc/PrometheusEndpointMvcTest.java +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/mvc/PrometheusEndpointMvcTest.java @@ -1,7 +1,7 @@ package at.tuwien.mvc; import at.tuwien.api.database.query.ExecuteStatementDto; -import at.tuwien.api.database.query.ImportCsvDto; +import at.tuwien.api.database.query.ImportDto; import at.tuwien.api.database.query.QueryPersistDto; import at.tuwien.api.database.table.TupleDeleteDto; import at.tuwien.api.database.table.TupleDto; @@ -196,17 +196,12 @@ public class PrometheusEndpointMvcTest extends AbstractUnitTest { /* ignore */ } try { - tableEndpoint.exportData(DATABASE_1_ID, TABLE_1_ID, null, USER_1_PRINCIPAL); + tableEndpoint.exportDataset(DATABASE_1_ID, TABLE_1_ID, null, USER_1_PRINCIPAL); } catch (Exception e) { /* ignore */ } try { - tableEndpoint.exportData(DATABASE_1_ID, TABLE_1_ID, null, USER_1_PRINCIPAL); - } catch (Exception e) { - /* ignore */ - } - try { - tableEndpoint.importDataset(DATABASE_1_ID, TABLE_1_ID, ImportCsvDto.builder().build(), USER_1_PRINCIPAL); + tableEndpoint.importDataset(DATABASE_1_ID, TABLE_1_ID, ImportDto.builder().build(), USER_1_PRINCIPAL); } catch (Exception e) { /* ignore */ } diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/SchemaServiceIntegrationTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/SchemaServiceIntegrationTest.java index 540e17850a535b8776daf4a6a7bf53a5499f1838..23503384b617ec7e066d9a0aeebe6c04c5f22a13 100644 --- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/SchemaServiceIntegrationTest.java +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/SchemaServiceIntegrationTest.java @@ -1,6 +1,5 @@ package at.tuwien.service; -import at.tuwien.api.container.image.ImageDateDto; import at.tuwien.api.database.ViewColumnDto; import at.tuwien.api.database.ViewDto; import at.tuwien.api.database.table.TableBriefDto; @@ -16,7 +15,8 @@ import at.tuwien.api.database.table.constraints.unique.UniqueDto; import at.tuwien.api.identifier.IdentifierDto; import at.tuwien.config.MariaDbConfig; import at.tuwien.config.MariaDbContainerConfig; -import at.tuwien.exception.*; +import at.tuwien.exception.TableNotFoundException; +import at.tuwien.exception.ViewNotFoundException; import at.tuwien.test.AbstractUnitTest; import lombok.extern.log4j.Log4j2; import org.junit.jupiter.api.BeforeEach; @@ -74,11 +74,11 @@ public class SchemaServiceIntegrationTest extends AbstractUnitTest { final List<ColumnDto> columns = response.getColumns(); assertNotNull(columns); assertEquals(5, columns.size()); - assertColumn(columns.get(0), null, null, DATABASE_1_ID, "id", "id", ColumnTypeDto.BIGINT, 19L, 0L, false, null, null); - assertColumn(columns.get(1), null, null, DATABASE_1_ID, "given_name", "given_name", ColumnTypeDto.VARCHAR, 255L, null, false, null, null); - assertColumn(columns.get(2), null, null, DATABASE_1_ID, "middle_name", "middle_name", ColumnTypeDto.VARCHAR, 255L, null, true, null, null); - assertColumn(columns.get(3), null, null, DATABASE_1_ID, "family_name", "family_name", ColumnTypeDto.VARCHAR, 255L, null, false, null, null); - assertColumn(columns.get(4), null, null, DATABASE_1_ID, "age", "age", ColumnTypeDto.INT, 10L, 0L, false, null, null); + assertColumn(columns.get(0), null, null, DATABASE_1_ID, "id", "id", ColumnTypeDto.BIGINT, 19L, 0L, false, null); + assertColumn(columns.get(1), null, null, DATABASE_1_ID, "given_name", "given_name", ColumnTypeDto.VARCHAR, 255L, null, false, null); + assertColumn(columns.get(2), null, null, DATABASE_1_ID, "middle_name", "middle_name", ColumnTypeDto.VARCHAR, 255L, null, true, null); + assertColumn(columns.get(3), null, null, DATABASE_1_ID, "family_name", "family_name", ColumnTypeDto.VARCHAR, 255L, null, false, null); + assertColumn(columns.get(4), null, null, DATABASE_1_ID, "age", "age", ColumnTypeDto.INT, 10L, 0L, false, null); final ConstraintsDto constraints = response.getConstraints(); assertNotNull(constraints); final Set<PrimaryKeyDto> primaryKey = constraints.getPrimaryKey(); @@ -127,11 +127,11 @@ public class SchemaServiceIntegrationTest extends AbstractUnitTest { final List<ColumnDto> columns = response.getColumns(); assertNotNull(columns); assertEquals(3, columns.size()); - assertColumn(columns.get(0), null, null, DATABASE_2_ID, "id", "id", ColumnTypeDto.BIGINT, 19L, 0L, false, null, null); - assertColumn(columns.get(1), null, null, DATABASE_2_ID, "mode", "mode", ColumnTypeDto.ENUM, 3L, null, false, null, null); + assertColumn(columns.get(0), null, null, DATABASE_2_ID, "id", "id", ColumnTypeDto.BIGINT, 19L, 0L, false, null); + assertColumn(columns.get(1), null, null, DATABASE_2_ID, "mode", "mode", ColumnTypeDto.ENUM, 3L, null, false, null); assertEquals(2, columns.get(1).getEnums().size()); assertEquals(List.of("ABC", "DEF"), columns.get(1).getEnums()); - assertColumn(columns.get(2), null, null, DATABASE_2_ID, "seq", "seq", ColumnTypeDto.SET, 5L, null, true, null, null); + assertColumn(columns.get(2), null, null, DATABASE_2_ID, "seq", "seq", ColumnTypeDto.SET, 5L, null, true, null); assertEquals(3, columns.get(2).getSets().size()); assertEquals(List.of("1", "2", "3"), columns.get(2).getSets()); /* ignore rest (constraints) */ @@ -167,11 +167,11 @@ public class SchemaServiceIntegrationTest extends AbstractUnitTest { final List<ColumnDto> columns = response.getColumns(); assertNotNull(columns); assertEquals(5, columns.size()); - assertColumn(columns.get(0), null, null, DATABASE_1_ID, "id", "id", ColumnTypeDto.BIGINT, 19L, 0L, false, null, null); - assertColumn(columns.get(1), null, null, DATABASE_1_ID, "date", "date", ColumnTypeDto.DATE, null, null, false, IMAGE_DATE_1_ID, null); - assertColumn(columns.get(2), null, null, DATABASE_1_ID, "location", "location", ColumnTypeDto.VARCHAR, 255L, null, true, null, "Closest city"); - assertColumn(columns.get(3), null, null, DATABASE_1_ID, "mintemp", "mintemp", ColumnTypeDto.DOUBLE, 22L, null, true, null, null); - assertColumn(columns.get(4), null, null, DATABASE_1_ID, "rainfall", "rainfall", ColumnTypeDto.DOUBLE, 22L, null, true, null, null); + assertColumn(columns.get(0), null, null, DATABASE_1_ID, "id", "id", ColumnTypeDto.BIGINT, 20L, 0L, false, null); + assertColumn(columns.get(1), null, null, DATABASE_1_ID, "date", "date", ColumnTypeDto.DATE, null, null, false, null); + assertColumn(columns.get(2), null, null, DATABASE_1_ID, "location", "location", ColumnTypeDto.VARCHAR, 255L, null, true, "Closest city"); + assertColumn(columns.get(3), null, null, DATABASE_1_ID, "mintemp", "mintemp", ColumnTypeDto.DOUBLE, 22L, null, true, null); + assertColumn(columns.get(4), null, null, DATABASE_1_ID, "rainfall", "rainfall", ColumnTypeDto.DOUBLE, 22L, null, true, null); final ConstraintsDto constraints = response.getConstraints(); final List<PrimaryKeyDto> primaryKey = new LinkedList<>(constraints.getPrimaryKey()); assertEquals(1, primaryKey.size()); @@ -194,6 +194,7 @@ public class SchemaServiceIntegrationTest extends AbstractUnitTest { assertEquals(1, uniques.size()); final UniqueDto unique0 = uniques.get(0); assertNotNull(unique0.getTable()); + assertEquals("some_constraint", unique0.getName()); assertNull(unique0.getTable().getId()); assertEquals(TABLE_1_INTERNALNAME, unique0.getTable().getName()); assertEquals(TABLE_1_INTERNALNAME, unique0.getTable().getInternalName()); @@ -358,9 +359,9 @@ public class SchemaServiceIntegrationTest extends AbstractUnitTest { assertEquals(ColumnTypeDto.BOOL, pk0.getColumn().getColumnType()); final List<ColumnDto> columns = response.getColumns(); assertEquals(3, columns.size()); - assertColumn(columns.get(0), null, null, DATABASE_1_ID, "bool_default", "bool_default", ColumnTypeDto.BOOL, null, 0L, false, null, null); - assertColumn(columns.get(1), null, null, DATABASE_1_ID, "bool_tinyint", "bool_tinyint", ColumnTypeDto.BOOL, null, 0L, false, null, null); - assertColumn(columns.get(2), null, null, DATABASE_1_ID, "bool_tinyint_unsigned", "bool_tinyint_unsigned", ColumnTypeDto.BOOL, null, 0L, false, null, null); + assertColumn(columns.get(0), null, null, DATABASE_1_ID, "bool_default", "bool_default", ColumnTypeDto.BOOL, null, 0L, false, null); + assertColumn(columns.get(1), null, null, DATABASE_1_ID, "bool_tinyint", "bool_tinyint", ColumnTypeDto.BOOL, null, 0L, false, null); + assertColumn(columns.get(2), null, null, DATABASE_1_ID, "bool_tinyint_unsigned", "bool_tinyint_unsigned", ColumnTypeDto.BOOL, null, 0L, false, null); } @Test @@ -397,9 +398,9 @@ public class SchemaServiceIntegrationTest extends AbstractUnitTest { assertEquals(DATABASE_1_ID, column3.getDatabaseId()); } - protected static void assertViewColumn(ViewColumnDto column, Long id, Long databaseId, String name, String internalName, - ColumnTypeDto type, Long size, Long d, Boolean nullAllowed, - ImageDateDto dateFormat, String description) { + protected static void assertViewColumn(ViewColumnDto column, Long id, Long databaseId, String name, + String internalName, ColumnTypeDto type, Long size, Long d, + Boolean nullAllowed, String description) { log.trace("assert column: {}", internalName); assertNotNull(column); assertEquals(id, column.getId()); @@ -411,17 +412,11 @@ public class SchemaServiceIntegrationTest extends AbstractUnitTest { assertEquals(d, column.getD()); assertEquals(nullAllowed, column.getIsNullAllowed()); assertEquals(description, column.getDescription()); - if (dateFormat != null) { - assertNotNull(column.getDateFormat()); - assertEquals(dateFormat.getId(), column.getDateFormat().getId()); - } else { - assertNull(column.getDateFormat()); - } } protected static void assertColumn(ColumnDto column, Long id, Long tableId, Long databaseId, String name, String internalName, ColumnTypeDto type, Long size, Long d, Boolean nullAllowed, - Long dfid, String description) { + String description) { log.trace("assert column: {}", internalName); assertNotNull(column); assertEquals(id, column.getId()); @@ -436,12 +431,6 @@ public class SchemaServiceIntegrationTest extends AbstractUnitTest { assertEquals(d, column.getD()); assertEquals(nullAllowed, column.getIsNullAllowed()); assertEquals(description, column.getDescription()); - if (dfid != null) { - assertNotNull(column.getDateFormat()); - assertEquals(dfid, column.getDateFormat().getId()); - } else { - assertNull(column.getDateFormat()); - } } } diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/SubsetServiceIntegrationTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/SubsetServiceIntegrationTest.java index aeaae0ecf2626ff88027a210bd8e24a5c66d4ede..b33a76506c15b77df3e0243754ca57b6dfcd9ed4 100644 --- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/SubsetServiceIntegrationTest.java +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/SubsetServiceIntegrationTest.java @@ -11,9 +11,10 @@ import at.tuwien.exception.*; import at.tuwien.gateway.DataDatabaseSidecarGateway; import at.tuwien.gateway.MetadataServiceGateway; import at.tuwien.test.AbstractUnitTest; +import at.tuwien.utils.FileUtils; import com.google.common.hash.Hashing; import lombok.extern.log4j.Log4j2; -import org.apache.commons.io.FileUtils; +import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.RandomUtils; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; @@ -387,13 +388,13 @@ public class SubsetServiceIntegrationTest extends AbstractUnitTest { protected void export_generic() throws StorageUnavailableException, SQLException, QueryMalformedException, SidecarExportException, MetadataServiceException, RemoteUnavailableException, StorageNotFoundException, IOException, InterruptedException { - final String filename = "68b329da9893e34099c7d8ad5cb9c940"; + final String filename = RandomStringUtils.randomAlphanumeric(40).toLowerCase() + ".tmp"; + EXPORT_RESOURCE_DTO.setFilename(filename); /* pre-condition */ Thread.sleep(1000) /* wait for test container some more */; /* mock */ - FileUtils.deleteQuietly(new File(s3Config.getS3FilePath() + "/" + filename)); doNothing() .when(dataDatabaseSidecarGateway) .exportFile(anyString(), anyInt(), eq(filename)); diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/TableServiceIntegrationTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/TableServiceIntegrationTest.java index e12b5bdc75962076ab52466b6c12493d109ccf64..7413b20462e7ba1968e9df86e4a83514f3835605 100644 --- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/TableServiceIntegrationTest.java +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/TableServiceIntegrationTest.java @@ -1,7 +1,6 @@ package at.tuwien.service; import at.tuwien.ExportResourceDto; -import at.tuwien.api.database.query.ImportCsvDto; import at.tuwien.api.database.query.QueryResultDto; import at.tuwien.api.database.table.*; import at.tuwien.api.database.table.columns.ColumnCreateDto; @@ -23,11 +22,7 @@ import at.tuwien.gateway.DataDatabaseSidecarGateway; import at.tuwien.gateway.MetadataServiceGateway; import at.tuwien.test.AbstractUnitTest; import lombok.extern.log4j.Log4j2; -import org.apache.commons.io.FileUtils; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.*; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; @@ -38,8 +33,6 @@ import org.testcontainers.containers.MariaDBContainer; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; -import java.io.File; -import java.io.IOException; import java.io.InputStream; import java.math.BigDecimal; import java.math.BigInteger; @@ -48,7 +41,6 @@ import java.time.Instant; import java.util.*; import static at.tuwien.service.SchemaServiceIntegrationTest.assertColumn; -import static at.tuwien.service.SchemaServiceIntegrationTest.assertViewColumn; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.doNothing; @@ -86,7 +78,9 @@ public class TableServiceIntegrationTest extends AbstractUnitTest { /* metadata database */ MariaDbConfig.dropDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_INTERNALNAME); MariaDbConfig.dropDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_2_INTERNALNAME); + MariaDbConfig.dropDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_3_INTERNALNAME); MariaDbConfig.createInitDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_DTO); + MariaDbConfig.createInitDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_3_DTO); } @Test @@ -252,6 +246,35 @@ public class TableServiceIntegrationTest extends AbstractUnitTest { assertEquals("0.2", result.get(0).get("rainfall")); } + @Test + public void createTuple_autogeneratedBlob_succeeds() throws SQLException, RemoteUnavailableException, ContainerNotFoundException, + TableNotFoundException, TableMalformedException, QueryMalformedException, StorageUnavailableException, + StorageNotFoundException, MetadataServiceException { + final String s3key = "2eec905f-17ed-41de-b12f-283c0aa3e4f9"; + final byte[] s3data = new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + /* add row with primary key */ + final TupleDto request = TupleDto.builder() + .data(new HashMap<>() {{ + put("value", "24.3"); + put("raw", s3key); + }}) + .build(); + + /* mock */ + when(metadataServiceGateway.getContainerById(CONTAINER_1_ID)) + .thenReturn(CONTAINER_1_PRIVILEGED_DTO); + when(storageService.getBytes(s3key)) + .thenReturn(s3data); + when(metadataServiceGateway.getTableById(DATABASE_3_ID, TABLE_8_ID)) + .thenReturn(TABLE_8_PRIVILEGED_DTO); + + /* test */ + tableService.createTuple(TABLE_8_PRIVILEGED_DTO, request); + final List<Map<String, byte[]>> result = MariaDbConfig.selectQueryByteArr(DATABASE_3_PRIVILEGED_DTO, "SELECT raw FROM mfcc WHERE raw IS NOT NULL", Set.of("raw")); + assertNotNull(result.get(0).get("raw")); + assertArrayEquals(s3data, result.get(0).get("raw")); + } + @Test public void createTuple_notInOrder_succeeds() throws SQLException, RemoteUnavailableException, ContainerNotFoundException, TableNotFoundException, TableMalformedException, QueryMalformedException, @@ -344,9 +367,9 @@ public class TableServiceIntegrationTest extends AbstractUnitTest { final List<ColumnDto> columns0 = table0.getColumns(); assertNotNull(columns0); Assertions.assertEquals(3, columns0.size()); - assertColumn(columns0.get(0), null, null, DATABASE_1_ID, "id", "id", ColumnTypeDto.BIGINT, 19L, 0L, false, null, null); - assertColumn(columns0.get(1), null, null, DATABASE_1_ID, "weather_id", "weather_id", ColumnTypeDto.BIGINT, 19L, 0L, false, null, null); - assertColumn(columns0.get(2), null, null, DATABASE_1_ID, "other_id", "other_id", ColumnTypeDto.BIGINT, 19L, 0L, false, null, null); + assertColumn(columns0.get(0), null, null, DATABASE_1_ID, "id", "id", ColumnTypeDto.BIGINT, 19L, 0L, false, null); + assertColumn(columns0.get(1), null, null, DATABASE_1_ID, "weather_id", "weather_id", ColumnTypeDto.BIGINT, 19L, 0L, false, null); + assertColumn(columns0.get(2), null, null, DATABASE_1_ID, "other_id", "other_id", ColumnTypeDto.BIGINT, 19L, 0L, false, null); final ConstraintsDto constraints0 = table0.getConstraints(); assertNotNull(constraints0); assertEquals(1, constraints0.getPrimaryKey().size()); @@ -391,8 +414,8 @@ public class TableServiceIntegrationTest extends AbstractUnitTest { final List<ColumnDto> columns1 = table1.getColumns(); assertNotNull(columns1); Assertions.assertEquals(2, columns1.size()); - assertColumn(columns1.get(0), null, null, DATABASE_1_ID, "id", "id", ColumnTypeDto.BIGINT, 19L, 0L, false, null, null); - assertColumn(columns1.get(1), null, null, DATABASE_1_ID, "other_id", "other_id", ColumnTypeDto.BIGINT, 19L, 0L, false, null, null); + assertColumn(columns1.get(0), null, null, DATABASE_1_ID, "id", "id", ColumnTypeDto.BIGINT, 19L, 0L, false, null); + assertColumn(columns1.get(1), null, null, DATABASE_1_ID, "other_id", "other_id", ColumnTypeDto.BIGINT, 19L, 0L, false, null); final ConstraintsDto constraints1 = table1.getConstraints(); assertNotNull(constraints1); assertEquals(2, constraints1.getPrimaryKey().size()); @@ -419,9 +442,9 @@ public class TableServiceIntegrationTest extends AbstractUnitTest { final List<ColumnDto> columns2 = table2.getColumns(); assertNotNull(columns2); Assertions.assertEquals(3, columns2.size()); - assertColumn(columns2.get(0), null, null, DATABASE_1_ID, "bool_default", "bool_default", ColumnTypeDto.BOOL, null, 0L, false, null, null); - assertColumn(columns2.get(1), null, null, DATABASE_1_ID, "bool_tinyint", "bool_tinyint", ColumnTypeDto.BOOL, null, 0L, false, null, null); - assertColumn(columns2.get(2), null, null, DATABASE_1_ID, "bool_tinyint_unsigned", "bool_tinyint_unsigned", ColumnTypeDto.BOOL, null, 0L, false, null, null); + assertColumn(columns2.get(0), null, null, DATABASE_1_ID, "bool_default", "bool_default", ColumnTypeDto.BOOL, null, 0L, false, null); + assertColumn(columns2.get(1), null, null, DATABASE_1_ID, "bool_tinyint", "bool_tinyint", ColumnTypeDto.BOOL, null, 0L, false, null); + assertColumn(columns2.get(2), null, null, DATABASE_1_ID, "bool_tinyint_unsigned", "bool_tinyint_unsigned", ColumnTypeDto.BOOL, null, 0L, false, null); final ConstraintsDto constraints2 = table2.getConstraints(); assertNotNull(constraints2); final Set<PrimaryKeyDto> primaryKey2 = constraints2.getPrimaryKey(); @@ -440,11 +463,11 @@ public class TableServiceIntegrationTest extends AbstractUnitTest { final List<ColumnDto> columns3 = table3.getColumns(); assertNotNull(columns3); Assertions.assertEquals(5, columns3.size()); - assertColumn(columns3.get(0), null, null, DATABASE_1_ID, "id", "id", ColumnTypeDto.BIGINT, 19L, 0L, false, null, null); - assertColumn(columns3.get(1), null, null, DATABASE_1_ID, "given_name", "given_name", ColumnTypeDto.VARCHAR, 255L, null, false, null, null); - assertColumn(columns3.get(2), null, null, DATABASE_1_ID, "middle_name", "middle_name", ColumnTypeDto.VARCHAR, 255L, null, true, null, null); - assertColumn(columns3.get(3), null, null, DATABASE_1_ID, "family_name", "family_name", ColumnTypeDto.VARCHAR, 255L, null, false, null, null); - assertColumn(columns3.get(4), null, null, DATABASE_1_ID, "age", "age", ColumnTypeDto.INT, 10L, 0L, false, null, null); + assertColumn(columns3.get(0), null, null, DATABASE_1_ID, "id", "id", ColumnTypeDto.BIGINT, 19L, 0L, false, null); + assertColumn(columns3.get(1), null, null, DATABASE_1_ID, "given_name", "given_name", ColumnTypeDto.VARCHAR, 255L, null, false, null); + assertColumn(columns3.get(2), null, null, DATABASE_1_ID, "middle_name", "middle_name", ColumnTypeDto.VARCHAR, 255L, null, true, null); + assertColumn(columns3.get(3), null, null, DATABASE_1_ID, "family_name", "family_name", ColumnTypeDto.VARCHAR, 255L, null, false, null); + assertColumn(columns3.get(4), null, null, DATABASE_1_ID, "age", "age", ColumnTypeDto.INT, 10L, 0L, false, null); final ConstraintsDto constraints3 = table3.getConstraints(); assertNotNull(constraints3); final Set<PrimaryKeyDto> primaryKey3 = constraints3.getPrimaryKey(); @@ -468,45 +491,43 @@ public class TableServiceIntegrationTest extends AbstractUnitTest { final TableDto response = tableService.createTable(DATABASE_1_PRIVILEGED_DTO, TABLE_4_CREATE_INTERNAL_DTO); assertEquals(TABLE_4_NAME, response.getName()); assertEquals(TABLE_4_INTERNALNAME, response.getInternalName()); - assertEquals(TABLE_4_COLUMNS.size(), response.getColumns().size()); + final List<ColumnDto> columns = response.getColumns(); + assertEquals(TABLE_4_COLUMNS.size(), columns.size()); + assertColumn(columns.get(0), null, null, DATABASE_1_ID, "timestamp", "timestamp", ColumnTypeDto.TIMESTAMP, null, null, false, null); + assertColumn(columns.get(1), null, null, DATABASE_1_ID, "value", "value", ColumnTypeDto.DECIMAL, 10L, 10L, true, null); + final ConstraintsDto constraints = response.getConstraints(); + assertNotNull(constraints); + final Set<PrimaryKeyDto> primaryKey = constraints.getPrimaryKey(); + Assertions.assertEquals(1, primaryKey.size()); + final Set<String> checks = constraints.getChecks(); + Assertions.assertEquals(0, checks.size()); } @Test + @Disabled("Not stable CI/CD") public void getStatistics_succeeds() throws TableMalformedException, SQLException, TableNotFoundException { /* test */ - final TableStatisticDto response = tableService.getStatistics(TABLE_1_PRIVILEGED_DTO); - assertEquals(TABLE_1_COLUMNS.size(), response.getColumns().size()); + final TableStatisticDto response = tableService.getStatistics(TABLE_2_PRIVILEGED_DTO); + assertEquals(TABLE_2_COLUMNS.size(), response.getColumns().size()); log.trace("response rows: {}", response.getRows()); assertEquals(3L, response.getRows()); - assertEquals(Set.of("id", "date", "location", "mintemp", "rainfall"), response.getColumns().keySet()); - final ColumnStatisticDto column0 = response.getColumns().get("id"); - assertEquals(BigDecimal.valueOf(1L), column0.getMin()); - assertEquals(BigDecimal.valueOf(3L), column0.getMax()); - assertNotNull(column0.getMean()); - assertNotNull(column0.getMedian()); - assertNotNull(column0.getStdDev()); - final ColumnStatisticDto column1 = response.getColumns().get("date"); - assertNull(column1.getMin()); - assertNull(column1.getMax()); - assertNull(column1.getMean()); - assertNull(column1.getMedian()); - assertNull(column1.getStdDev()); - final ColumnStatisticDto column2 = response.getColumns().get("location"); - assertNull(column2.getMin()); - assertNull(column2.getMax()); - assertNull(column2.getMean()); - assertNull(column2.getMedian()); - assertNull(column2.getStdDev()); - final ColumnStatisticDto column3 = response.getColumns().get("mintemp"); - assertEquals(BigDecimal.valueOf(7.4), column3.getMin()); - assertEquals(BigDecimal.valueOf(13.4), column3.getMax()); + assertEquals(Set.of("location", "lat", "lng"), response.getColumns().keySet()); + final ColumnStatisticDto column0 = response.getColumns().get("location"); + assertNull(column0.getMin()); + assertNull(column0.getMax()); + assertNull(column0.getMean()); + assertNull(column0.getMedian()); + assertNull(column0.getStdDev()); + final ColumnStatisticDto column3 = response.getColumns().get("lat"); + assertEquals(BigDecimal.valueOf(-36.0653583), column3.getMin()); + assertEquals(BigDecimal.valueOf(-33.847927), column3.getMax()); assertNotNull(column3.getMean()); assertNotNull(column3.getMedian()); assertNotNull(column3.getStdDev()); - final ColumnStatisticDto column4 = response.getColumns().get("rainfall"); - assertEquals(BigDecimal.valueOf(0L), column4.getMin()); - assertEquals(BigDecimal.valueOf(0.6), column4.getMax()); + final ColumnStatisticDto column4 = response.getColumns().get("lng"); + assertEquals(BigDecimal.valueOf(146.9112214), column4.getMin()); + assertEquals(BigDecimal.valueOf(150.6517942), column4.getMax()); assertNotNull(column4.getMean()); assertNotNull(column4.getMedian()); assertNotNull(column4.getStdDev()); @@ -532,6 +553,66 @@ public class TableServiceIntegrationTest extends AbstractUnitTest { }); } + @Test + public void create_compositePrimaryKey_fails() throws TableNotFoundException, TableMalformedException, SQLException, + TableExistsException { + final at.tuwien.api.database.table.internal.TableCreateDto request = TableCreateDto.builder() + .name("composite_primary_key") + .columns(List.of(ColumnCreateDto.builder() + .name("name") + .type(ColumnTypeDto.VARCHAR) + .size(255L) + .nullAllowed(false) + .build(), + ColumnCreateDto.builder() + .name("lat") + .type(ColumnTypeDto.DECIMAL) + .size(10L) + .d(10L) + .nullAllowed(false) + .build(), + ColumnCreateDto.builder() + .name("lng") + .type(ColumnTypeDto.DECIMAL) + .size(10L) + .d(10L) + .nullAllowed(false) + .build())) + .constraints(ConstraintsCreateDto.builder() + .primaryKey(Set.of("lat", "lng")) + .foreignKeys(List.of()) + .checks(Set.of()) + .uniques(List.of()) + .build()) + .build(); + + /* test */ + final TableDto response = tableService.createTable(DATABASE_1_PRIVILEGED_DTO, request); + assertEquals("composite_primary_key", response.getName()); + assertEquals("composite_primary_key", response.getInternalName()); + final List<ColumnDto> columns = response.getColumns(); + assertEquals(3, columns.size()); + assertColumn(columns.get(0), null, null, DATABASE_1_ID, "name", "name", ColumnTypeDto.VARCHAR, 255L, null, false, null); + assertColumn(columns.get(1), null, null, DATABASE_1_ID, "lat", "lat", ColumnTypeDto.DECIMAL, 10L, 10L, false, null); + assertColumn(columns.get(2), null, null, DATABASE_1_ID, "lng", "lng", ColumnTypeDto.DECIMAL, 10L, 10L, false, null); + final ConstraintsDto constraints = response.getConstraints(); + assertNotNull(constraints); + final Set<String> checks = constraints.getChecks(); + assertNotNull(checks); + assertEquals(0, checks.size()); + final List<PrimaryKeyDto> primaryKeys = new LinkedList<>(constraints.getPrimaryKey()); + assertNotNull(primaryKeys); + assertEquals(2, primaryKeys.size()); + assertEquals("lat", primaryKeys.get(0).getColumn().getInternalName()); + assertEquals("lng", primaryKeys.get(1).getColumn().getInternalName()); + final List<ForeignKeyDto> foreignKeys = constraints.getForeignKeys(); + assertNotNull(foreignKeys); + assertEquals(0, foreignKeys.size()); + final List<UniqueDto> uniques = constraints.getUniques(); + assertNotNull(uniques); + assertEquals(0, uniques.size()); + } + @Test public void create_needSequence_succeeds() throws TableNotFoundException, TableMalformedException, SQLException, TableExistsException { @@ -660,53 +741,6 @@ public class TableServiceIntegrationTest extends AbstractUnitTest { }); } - @Test - public void importDataset_withSeparatorAndQuoteAndNullElement_succeeds() throws SidecarImportException, - SQLException, QueryMalformedException, RemoteUnavailableException, StorageNotFoundException, IOException { - final ImportCsvDto request = ImportCsvDto.builder() - .location("weather_aus.csv") - .separator(';') - .quote('"') - .nullElement("NA") - .build(); - - /* mock */ - final File source = new File("src/test/resources/csv/weather_aus.csv"); - final File target = new File("/tmp/weather_aus.csv"); - log.trace("copy dataset from {} to {}", source.toPath().toAbsolutePath(), target.toPath().toAbsolutePath()); - FileUtils.copyFile(source, target); - doNothing() - .when(dataDatabaseSidecarGateway) - .importFile(anyString(), anyInt(), eq("weather_aus.csv")); - - /* test */ - tableService.importDataset(TABLE_1_PRIVILEGED_DTO, request); - } - - @Test - public void importDataset_malformedData_fails() throws RemoteUnavailableException, StorageNotFoundException, - IOException, SidecarImportException { - final ImportCsvDto request = ImportCsvDto.builder() - .location("weather_aus.csv") - .separator(';') - .quote('"') - .build(); - - /* mock */ - final File source = new File("src/test/resources/csv/weather_aus.csv"); - final File target = new File("/tmp/weather_aus.csv"); - log.trace("copy dataset from {} to {}", source.toPath().toAbsolutePath(), target.toPath().toAbsolutePath()); - FileUtils.copyFile(source, target); - doNothing() - .when(dataDatabaseSidecarGateway) - .importFile(anyString(), anyInt(), eq("weather_aus.csv")); - - /* test */ - assertThrows(QueryMalformedException.class, () -> { - tableService.importDataset(TABLE_1_PRIVILEGED_DTO, request); - }); - } - @Test public void exportDataset_succeeds() throws SQLException, QueryMalformedException, RemoteUnavailableException, StorageNotFoundException, StorageUnavailableException, SidecarExportException { diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/ViewServiceIntegrationTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/ViewServiceIntegrationTest.java index 20a769f8ce8e8b8a5f4cdf1f4e42610e0e3f561d..5f20464eb9f252164c037a2155cd661d24d9019a 100644 --- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/ViewServiceIntegrationTest.java +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/ViewServiceIntegrationTest.java @@ -3,7 +3,6 @@ package at.tuwien.service; import at.tuwien.api.database.ViewColumnDto; import at.tuwien.api.database.ViewDto; import at.tuwien.api.database.query.QueryResultDto; -import at.tuwien.api.database.table.columns.ColumnDto; import at.tuwien.config.MariaDbConfig; import at.tuwien.config.MariaDbContainerConfig; import at.tuwien.exception.*; @@ -24,7 +23,6 @@ import java.time.Instant; import java.util.List; import java.util.Map; -import static at.tuwien.service.SchemaServiceIntegrationTest.assertViewColumn; import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -68,11 +66,11 @@ public class ViewServiceIntegrationTest extends AbstractUnitTest { final List<ViewColumnDto> columns = response.getColumns(); assertEquals(VIEW_1_COLUMNS.size(), columns.size()); ViewColumnDto ref = VIEW_1_COLUMNS_DTO.get(0); - SchemaServiceIntegrationTest.assertViewColumn(columns.get(0), null, ref.getDatabaseId(), ref.getName(), ref.getInternalName(), ref.getColumnType(), ref.getSize(), ref.getD(), ref.getIsNullAllowed(), ref.getDateFormat(), ref.getDescription()); + SchemaServiceIntegrationTest.assertViewColumn(columns.get(0), null, ref.getDatabaseId(), ref.getName(), ref.getInternalName(), ref.getColumnType(), ref.getSize(), ref.getD(), ref.getIsNullAllowed(), ref.getDescription()); ref = VIEW_1_COLUMNS_DTO.get(1); - SchemaServiceIntegrationTest.assertViewColumn(columns.get(1), null, ref.getDatabaseId(), ref.getName(), ref.getInternalName(), ref.getColumnType(), ref.getSize(), ref.getD(), ref.getIsNullAllowed(), ref.getDateFormat(), ref.getDescription()); + SchemaServiceIntegrationTest.assertViewColumn(columns.get(1), null, ref.getDatabaseId(), ref.getName(), ref.getInternalName(), ref.getColumnType(), ref.getSize(), ref.getD(), ref.getIsNullAllowed(), ref.getDescription()); ref = VIEW_1_COLUMNS_DTO.get(2); - SchemaServiceIntegrationTest.assertViewColumn(columns.get(2), null, ref.getDatabaseId(), ref.getName(), ref.getInternalName(), ref.getColumnType(), ref.getSize(), ref.getD(), ref.getIsNullAllowed(), ref.getDateFormat(), ref.getDescription()); + SchemaServiceIntegrationTest.assertViewColumn(columns.get(2), null, ref.getDatabaseId(), ref.getName(), ref.getInternalName(), ref.getColumnType(), ref.getSize(), ref.getD(), ref.getIsNullAllowed(), ref.getDescription()); } diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/utils/FileUtils.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/utils/FileUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..5746d8dfcfa1de0be7bd707e1c8b3cabf3e82d30 --- /dev/null +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/utils/FileUtils.java @@ -0,0 +1,14 @@ +package at.tuwien.utils; + +import java.io.File; +import java.io.IOException; + +public class FileUtils { + + public static void delete(File file) throws IOException { + if (file.exists()) { + org.apache.commons.io.FileUtils.forceDelete(file); + } + } + +} diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/utils/UserUtilTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/utils/UserUtilTest.java index 13806e93ddd1cbeb7a8e1c0ab4e0fe38db0830ad..13ddfce8d3c171b79096d2e0d1d05948848a8c86 100644 --- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/utils/UserUtilTest.java +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/utils/UserUtilTest.java @@ -8,6 +8,13 @@ import static org.junit.jupiter.api.Assertions.*; public class UserUtilTest extends BaseTest { + @Test + public void constructor_succeeds() { + + /* test */ + new UserUtil(); + } + @Test public void hasRole_succeeds() { assertTrue(UserUtil.hasRole(USER_1_PRINCIPAL, "find-container")); diff --git a/dbrepo-data-service/rest-service/src/test/resources/init/musicology.sql b/dbrepo-data-service/rest-service/src/test/resources/init/musicology.sql index 4d2c8deb43ede5de84cd321a302e97ef84038508..a2fc3f2b313cdd536e8ccba075bf7353be2b1438 100644 --- a/dbrepo-data-service/rest-service/src/test/resources/init/musicology.sql +++ b/dbrepo-data-service/rest-service/src/test/resources/init/musicology.sql @@ -6,7 +6,8 @@ CREATE SEQUENCE seq_mfcc; CREATE TABLE mfcc ( id BIGINT PRIMARY KEY NOT NULL DEFAULT nextval(`seq_mfcc`), - value DECIMAL NOT NULL + value DECIMAL NOT NULL, + raw LONGBLOB NULL ) WITH SYSTEM VERSIONING; INSERT INTO `mfcc` (`value`) diff --git a/dbrepo-data-service/rest-service/src/test/resources/init/querystore.sql b/dbrepo-data-service/rest-service/src/test/resources/init/querystore.sql index c1df44d1b0766fb04d081f3b5b3679039d8ba72f..3e7471df3e1eb3a1bb79db7246ecb805a06f495c 100644 --- a/dbrepo-data-service/rest-service/src/test/resources/init/querystore.sql +++ b/dbrepo-data-service/rest-service/src/test/resources/init/querystore.sql @@ -1,5 +1,5 @@ CREATE SEQUENCE `qs_queries_seq` NOCACHE; -CREATE TABLE `qs_queries` ( `id` bigint not null primary key default nextval(`qs_queries_seq`), `created` datetime not null default now(), `executed` datetime not null default now(), `created_by` varchar(36) not null, `query` text not null, `query_normalized` text not null, `is_persisted` boolean not null, `query_hash` varchar(255) not null, `result_hash` varchar(255), `result_number` bigint ) WITH SYSTEM VERSIONING; +CREATE TABLE `qs_queries` ( `id` bigint not null primary key default nextval(`qs_queries_seq`), `created` datetime not null default now(), `executed` datetime not null default now(), `created_by` varchar(36), `query` text not null, `query_normalized` text not null, `is_persisted` boolean not null, `query_hash` varchar(255) not null, `result_hash` varchar(255), `result_number` bigint ) WITH SYSTEM VERSIONING; CREATE PROCEDURE hash_table(IN name VARCHAR(255), OUT hash VARCHAR(255), OUT count BIGINT) BEGIN DECLARE _sql TEXT; SELECT CONCAT('SELECT SHA2(GROUP_CONCAT(CONCAT_WS(\'\',', GROUP_CONCAT(CONCAT('`', column_name, '`') ORDER BY column_name), ') SEPARATOR \',\'), 256) AS hash, COUNT(*) AS count FROM `', name, '` INTO @hash, @count;') FROM `information_schema`.`columns` WHERE `table_schema` = DATABASE() AND `table_name` = name INTO _sql; PREPARE stmt FROM _sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET hash = @hash; SET count = @count; END; CREATE PROCEDURE store_query(IN query TEXT, IN executed DATETIME, OUT queryId BIGINT) BEGIN DECLARE _queryhash varchar(255) DEFAULT SHA2(query, 256); DECLARE _username varchar(255) DEFAULT REGEXP_REPLACE(current_user(), '@.*', ''); DECLARE _query TEXT DEFAULT CONCAT('CREATE OR REPLACE TABLE _tmp AS (', query, ')'); PREPARE stmt FROM _query; EXECUTE stmt; DEALLOCATE PREPARE stmt; CALL hash_table('_tmp', @hash, @count); DROP TABLE IF EXISTS `_tmp`; IF @hash IS NULL THEN INSERT INTO `qs_queries` (`created_by`, `query`, `query_normalized`, `is_persisted`, `query_hash`, `result_hash`, `result_number`, `executed`) SELECT _username, query, query, false, _queryhash, @hash, @count, executed WHERE NOT EXISTS (SELECT `id` FROM `qs_queries` WHERE `query_hash` = _queryhash AND `result_hash` IS NULL); SET queryId = (SELECT `id` FROM `qs_queries` WHERE `query_hash` = _queryhash AND `result_hash` IS NULL); ELSE INSERT INTO `qs_queries` (`created_by`, `query`, `query_normalized`, `is_persisted`, `query_hash`, `result_hash`, `result_number`, `executed`) SELECT _username, query, query, false, _queryhash, @hash, @count, executed WHERE NOT EXISTS (SELECT `id` FROM `qs_queries` WHERE `query_hash` = _queryhash AND `result_hash` = @hash); SET queryId = (SELECT `id` FROM `qs_queries` WHERE `query_hash` = _queryhash AND `result_hash` = @hash); END IF; END; CREATE DEFINER = 'root' PROCEDURE _store_query(IN _username VARCHAR(255), IN query TEXT, IN executed DATETIME, OUT queryId BIGINT) BEGIN DECLARE _queryhash varchar(255) DEFAULT SHA2(query, 256); DECLARE _query TEXT DEFAULT CONCAT('CREATE OR REPLACE TABLE _tmp AS (', query, ')'); PREPARE stmt FROM _query; EXECUTE stmt; DEALLOCATE PREPARE stmt; CALL hash_table('_tmp', @hash, @count); DROP TABLE IF EXISTS `_tmp`; IF @hash IS NULL THEN INSERT INTO `qs_queries` (`created_by`, `query`, `query_normalized`, `is_persisted`, `query_hash`, `result_hash`, `result_number`, `executed`) SELECT _username, query, query, false, _queryhash, @hash, @count, executed WHERE NOT EXISTS (SELECT `id` FROM `qs_queries` WHERE `query_hash` = _queryhash AND `result_hash` IS NULL); SET queryId = (SELECT `id` FROM `qs_queries` WHERE `query_hash` = _queryhash AND `result_hash` IS NULL); ELSE INSERT INTO `qs_queries` (`created_by`, `query`, `query_normalized`, `is_persisted`, `query_hash`, `result_hash`, `result_number`, `executed`) SELECT _username, query, query, false, _queryhash, @hash, @count, executed WHERE NOT EXISTS (SELECT `id` FROM `qs_queries` WHERE `query_hash` = _queryhash AND `result_hash` = @hash); SET queryId = (SELECT `id` FROM `qs_queries` WHERE `query_hash` = _queryhash AND `result_hash` = @hash); END IF; END; \ No newline at end of file diff --git a/dbrepo-data-service/rest-service/src/test/resources/init/weather.sql b/dbrepo-data-service/rest-service/src/test/resources/init/weather.sql index 7c3ca99ce39f61755752d2ecbb607ad6ed86e386..322e67cc07397105bb7c763efe4d37c905cc1b18 100644 --- a/dbrepo-data-service/rest-service/src/test/resources/init/weather.sql +++ b/dbrepo-data-service/rest-service/src/test/resources/init/weather.sql @@ -11,13 +11,13 @@ CREATE TABLE weather_location CREATE TABLE weather_aus ( - id BIGINT NOT NULL PRIMARY KEY, + id SERIAL PRIMARY KEY, `date` DATE NOT NULL, location VARCHAR(255) NULL COMMENT 'Closest city', mintemp DOUBLE PRECISION NULL, rainfall DOUBLE PRECISION NULL, FOREIGN KEY (location) REFERENCES weather_location (location) ON DELETE SET NULL, - UNIQUE (`date`), + CONSTRAINT some_constraint UNIQUE (`date`), CHECK (`mintemp` > 0) ) WITH SYSTEM VERSIONING COMMENT 'Weather in Australia'; diff --git a/dbrepo-data-service/services/pom.xml b/dbrepo-data-service/services/pom.xml index 0b57ceef9d0e575cdedd03c769ecc24aacf682e5..ab57ee97af68a230a6ffb39673b8b9b6eb3a2ace 100644 --- a/dbrepo-data-service/services/pom.xml +++ b/dbrepo-data-service/services/pom.xml @@ -6,12 +6,12 @@ <parent> <groupId>at.tuwien</groupId> <artifactId>dbrepo-data-service</artifactId> - <version>1.4.5</version> + <version>1.4.7</version> </parent> <artifactId>services</artifactId> <name>dbrepo-data-service-services</name> - <version>1.4.5</version> + <version>1.4.7</version> <dependencies> <dependency> @@ -22,7 +22,7 @@ <dependency> <groupId>at.tuwien</groupId> <artifactId>dbrepo-data-service-querystore</artifactId> - <version>1.4.5</version> + <version>1.4.7</version> </dependency> </dependencies> diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/config/KeycloakConfig.java b/dbrepo-data-service/services/src/main/java/at/tuwien/config/KeycloakConfig.java index e0d7d0321513387f1e1c9c235c1c4b51e309be1d..cc6960ba39be294a61e059f3a3f45ecfc8e820fd 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/config/KeycloakConfig.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/config/KeycloakConfig.java @@ -1,12 +1,8 @@ package at.tuwien.config; -import at.tuwien.interceptor.KeycloakInterceptor; import lombok.Getter; import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.web.client.RestTemplate; -import org.springframework.web.util.DefaultUriBuilderFactory; @Getter @Configuration @@ -26,13 +22,4 @@ public class KeycloakConfig { @Value("${dbrepo.keycloak.clientSecret}") private String keycloakClientSecret; - - @Bean("keycloakRestTemplate") - public RestTemplate brokerRestTemplate() { - final RestTemplate restTemplate = new RestTemplate(); - restTemplate.setUriTemplateHandler(new DefaultUriBuilderFactory(keycloakEndpoint)); - restTemplate.getInterceptors() - .add(new KeycloakInterceptor(keycloakUsername, keycloakPassword, keycloakEndpoint)); - return restTemplate; - } } diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/config/MetricsConfig.java b/dbrepo-data-service/services/src/main/java/at/tuwien/config/MetricsConfig.java index 450be2f7df8b52fe493dd498dc0422350bb3ff39..9ff09ab42b2c2e62536e1d46fa986057ff664d53 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/config/MetricsConfig.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/config/MetricsConfig.java @@ -1,5 +1,7 @@ package at.tuwien.config; +import io.micrometer.core.instrument.Counter; +import io.micrometer.core.instrument.Metrics; import io.micrometer.observation.ObservationRegistry; import io.micrometer.observation.aop.ObservedAspect; import org.springframework.context.annotation.Bean; @@ -12,4 +14,20 @@ public class MetricsConfig { public ObservedAspect observedAspect(ObservationRegistry observationRegistry) { return new ObservedAspect(observationRegistry); } + + @Bean + public Counter httpDataAccessCounter() { + return Counter.builder("dbrepo.data.access") + .tag("protocol", "http") + .description("The total number of accessed data sources") + .register(Metrics.globalRegistry); + } + + @Bean + public Counter amqpDataAccessCounter() { + return Counter.builder("dbrepo.data.access") + .tag("protocol", "amqp") + .description("The total number of accessed data sources") + .register(Metrics.globalRegistry); + } } diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/config/WebSecurityConfig.java b/dbrepo-data-service/services/src/main/java/at/tuwien/config/WebSecurityConfig.java index 1560c14b7aaa6272c76515a734a1ad99f7075222..e1f763b3b7924748fe80f4485bbef2d3b05cfa23 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/config/WebSecurityConfig.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/config/WebSecurityConfig.java @@ -54,7 +54,8 @@ public class WebSecurityConfig { ); final OrRequestMatcher publicEndpoints = new OrRequestMatcher( new AntPathRequestMatcher("/api/**", "GET"), - new AntPathRequestMatcher("/api/**", "HEAD") + new AntPathRequestMatcher("/api/**", "HEAD"), + new AntPathRequestMatcher("/api/database/**/subset", "POST") ); /* enable CORS and disable CSRF */ http = http.cors().and().csrf().disable(); diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/MetadataServiceGateway.java b/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/MetadataServiceGateway.java index d16c8c8eba81efd22a64757a6dd1eb51dc56318f..282e7d593feec58991dc9f4530e3314fa208eb29 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/MetadataServiceGateway.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/MetadataServiceGateway.java @@ -8,6 +8,7 @@ import at.tuwien.api.database.table.TableStatisticDto; import at.tuwien.api.database.table.internal.PrivilegedTableDto; import at.tuwien.api.identifier.IdentifierDto; import at.tuwien.api.user.PrivilegedUserDto; +import at.tuwien.api.user.UserBriefDto; import at.tuwien.api.user.UserDto; import at.tuwien.exception.*; import jakarta.validation.constraints.NotNull; @@ -22,9 +23,9 @@ public interface MetadataServiceGateway { * * @param containerId The container id * @return The container with privileged connection information, if successful. - * @throws ContainerNotFoundException The table was not found in the metadata service. + * @throws ContainerNotFoundException The table was not found in the metadata service. * @throws RemoteUnavailableException The remote service is not available. - * @throws MetadataServiceException The remote service returned invalid data. + * @throws MetadataServiceException The remote service returned invalid data. */ PrivilegedContainerDto getContainerById(Long containerId) throws RemoteUnavailableException, ContainerNotFoundException, MetadataServiceException; @@ -36,7 +37,7 @@ public interface MetadataServiceGateway { * @return The database, if successful. * @throws DatabaseNotFoundException The database was not found in the metadata service. * @throws RemoteUnavailableException The remote service is not available. - * @throws MetadataServiceException The remote service returned invalid data. + * @throws MetadataServiceException The remote service returned invalid data. */ PrivilegedDatabaseDto getDatabaseById(Long id) throws DatabaseNotFoundException, RemoteUnavailableException, MetadataServiceException; @@ -48,7 +49,7 @@ public interface MetadataServiceGateway { * @return The database, if successful. * @throws DatabaseNotFoundException The database was not found in the metadata service. * @throws RemoteUnavailableException The remote service is not available. - * @throws MetadataServiceException The remote service returned invalid data. + * @throws MetadataServiceException The remote service returned invalid data. */ PrivilegedDatabaseDto getDatabaseByInternalName(String internalName) throws DatabaseNotFoundException, RemoteUnavailableException, MetadataServiceException; @@ -61,19 +62,20 @@ public interface MetadataServiceGateway { * @return The table, if successful. * @throws TableNotFoundException The table was not found in the metadata service. * @throws RemoteUnavailableException The remote service is not available. - * @throws MetadataServiceException The remote service returned invalid data. + * @throws MetadataServiceException The remote service returned invalid data. */ PrivilegedTableDto getTableById(Long databaseId, Long id) throws TableNotFoundException, RemoteUnavailableException, MetadataServiceException; /** * Get a view with given database id and view id from the metadata service. + * * @param databaseId The database id. * @param id The view id. * @return The view, if successful. - * @throws ViewNotFoundException The view was not found in the metadata service. + * @throws ViewNotFoundException The view was not found in the metadata service. * @throws RemoteUnavailableException The remote service is not available. - * @throws MetadataServiceException The remote service returned invalid data. + * @throws MetadataServiceException The remote service returned invalid data. */ PrivilegedViewDto getViewById(Long databaseId, Long id) throws RemoteUnavailableException, ViewNotFoundException, MetadataServiceException; @@ -85,10 +87,21 @@ public interface MetadataServiceGateway { * @return The user, if successful. * @throws RemoteUnavailableException The remote service is not available and invalid data was returned. * @throws UserNotFoundException The user was not found in the metadata service. - * @throws MetadataServiceException The remote service returned invalid data. + * @throws MetadataServiceException The remote service returned invalid data. */ UserDto getUserById(UUID userId) throws RemoteUnavailableException, UserNotFoundException, MetadataServiceException; + /** + * Get a user with given username from the metadata service. + * + * @return The user, if successful. Otherwise empty list. + * @throws RemoteUnavailableException The remote service is not available and invalid data was returned. + * @throws UserNotFoundException The user was not found in the metadata service. + * @throws MetadataServiceException The remote service returned invalid data. + */ + UUID getSystemUserId() throws RemoteUnavailableException, UserNotFoundException, + MetadataServiceException; + /** * Get a user with given user id from the metadata service. * @@ -96,42 +109,45 @@ public interface MetadataServiceGateway { * @return The user, if successful. * @throws RemoteUnavailableException The remote service is not available and invalid data was returned. * @throws UserNotFoundException The user was not found in the metadata service. - * @throws MetadataServiceException The remote service returned invalid data. + * @throws MetadataServiceException The remote service returned invalid data. */ PrivilegedUserDto getPrivilegedUserById(UUID userId) throws RemoteUnavailableException, UserNotFoundException, MetadataServiceException; /** * Get database access for a given user and database id from the metadata service. + * * @param databaseId The database id. - * @param userId The user id. + * @param userId The user id. * @return The database access, if successful. * @throws RemoteUnavailableException The remote service is not available and invalid data was returned. - * @throws NotAllowedException The access to this database is denied for the given user. - * @throws MetadataServiceException The remote service returned invalid data. + * @throws NotAllowedException The access to this database is denied for the given user. + * @throws MetadataServiceException The remote service returned invalid data. */ DatabaseAccessDto getAccess(Long databaseId, UUID userId) throws RemoteUnavailableException, NotAllowedException, MetadataServiceException; /** * Get a list of identifiers for a given database id and optional subset id. + * * @param databaseId The database id. - * @param subsetId The subset id. Optional. + * @param subsetId The subset id. Optional. * @return The list of identifiers. * @throws RemoteUnavailableException The remote service is not available and invalid data was returned. - * @throws DatabaseNotFoundException The database was not found. - * @throws MetadataServiceException The remote service returned invalid data. + * @throws DatabaseNotFoundException The database was not found. + * @throws MetadataServiceException The remote service returned invalid data. */ List<IdentifierDto> getIdentifiers(@NotNull Long databaseId, Long subsetId) throws MetadataServiceException, RemoteUnavailableException, DatabaseNotFoundException; /** * Update the table statistics in the metadata service. + * * @param databaseId The database id. - * @param tableId The table id. + * @param tableId The table id. * @throws RemoteUnavailableException The remote service is not available and invalid data was returned. - * @throws TableNotFoundException The table was not found. - * @throws MetadataServiceException The remote service returned invalid data. + * @throws TableNotFoundException The table was not found. + * @throws MetadataServiceException The remote service returned invalid data. */ void updateTableStatistics(Long databaseId, Long tableId) throws TableNotFoundException, MetadataServiceException, RemoteUnavailableException; } diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/impl/MetadataServiceGatewayImpl.java b/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/impl/MetadataServiceGatewayImpl.java index b4cb2ff5043c46e1e5ece49a45690ef04782bd3c..11a90afde703a353e9f5b539394806d6356fe73c 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/impl/MetadataServiceGatewayImpl.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/impl/MetadataServiceGatewayImpl.java @@ -10,7 +10,9 @@ import at.tuwien.api.database.table.TableDto; import at.tuwien.api.database.table.internal.PrivilegedTableDto; import at.tuwien.api.identifier.IdentifierDto; import at.tuwien.api.user.PrivilegedUserDto; +import at.tuwien.api.user.UserBriefDto; import at.tuwien.api.user.UserDto; +import at.tuwien.config.GatewayConfig; import at.tuwien.exception.*; import at.tuwien.gateway.MetadataServiceGateway; import at.tuwien.mapper.MetadataMapper; @@ -35,11 +37,14 @@ import java.util.UUID; public class MetadataServiceGatewayImpl implements MetadataServiceGateway { private final RestTemplate restTemplate; + private final GatewayConfig gatewayConfig; private final MetadataMapper metadataMapper; @Autowired - public MetadataServiceGatewayImpl(RestTemplate restTemplate, MetadataMapper metadataMapper) { + public MetadataServiceGatewayImpl(RestTemplate restTemplate, GatewayConfig gatewayConfig, + MetadataMapper metadataMapper) { this.restTemplate = restTemplate; + this.gatewayConfig = gatewayConfig; this.metadataMapper = metadataMapper; } @@ -61,8 +66,11 @@ public class MetadataServiceGatewayImpl implements MetadataServiceGateway { log.error("Failed to find container with id {}: service responded unsuccessful: {}", containerId, response.getStatusCode()); throw new MetadataServiceException("Failed to find container: service responded unsuccessful: " + response.getStatusCode()); } - if (!response.getHeaders().keySet().containsAll(List.of("X-Username", "X-Password"))) { + final List<String> expectedHeaders = List.of("X-Username", "X-Password"); + if (!response.getHeaders().keySet().containsAll(expectedHeaders)) { log.error("Failed to find all privileged container headers"); + log.debug("expected headers: {}", expectedHeaders); + log.debug("found headers: {}", response.getHeaders().keySet()); throw new MetadataServiceException("Failed to find all privileged container headers"); } if (response.getBody() == null) { @@ -93,8 +101,11 @@ public class MetadataServiceGatewayImpl implements MetadataServiceGateway { log.error("Failed to find database with id {}: service responded unsuccessful: {}", id, response.getStatusCode()); throw new MetadataServiceException("Failed to find database: service responded unsuccessful: " + response.getStatusCode()); } - if (!response.getHeaders().keySet().containsAll(List.of("X-Username", "X-Password"))) { + final List<String> expectedHeaders = List.of("X-Username", "X-Password"); + if (!response.getHeaders().keySet().containsAll(expectedHeaders)) { log.error("Failed to find all privileged database headers"); + log.debug("expected headers: {}", expectedHeaders); + log.debug("found headers: {}", response.getHeaders().keySet()); throw new MetadataServiceException("Failed to find all privileged database headers"); } if (response.getBody() == null) { @@ -118,14 +129,22 @@ public class MetadataServiceGatewayImpl implements MetadataServiceGateway { log.error("Failed to find database with internal name {}: {}", internalName, e.getMessage()); throw new RemoteUnavailableException("Failed to find database: " + e.getMessage(), e); } - if (!response.getStatusCode().equals(HttpStatus.OK) || response.getBody() == null) { + if (!response.getStatusCode().equals(HttpStatus.OK)) { log.error("Failed to find database with internal name {}: service responded unsuccessful: {}", internalName, response.getStatusCode()); throw new MetadataServiceException("Failed to find database: service responded unsuccessful: " + response.getStatusCode()); } - if (response.getBody().length != 1) { + /* body first, then headers next */ + if (response.getBody() == null || response.getBody().length != 1) { log.error("Failed to find database with internal name {}: body is empty", internalName); throw new DatabaseNotFoundException("Failed to find database: body is empty"); } + final List<String> expectedHeaders = List.of("X-Username", "X-Password"); + if (!response.getHeaders().keySet().containsAll(expectedHeaders)) { + log.error("Failed to find all privileged database headers"); + log.debug("expected headers: {}", expectedHeaders); + log.debug("found headers: {}", response.getHeaders().keySet()); + throw new MetadataServiceException("Failed to find all privileged database headers"); + } return response.getBody()[0]; } @@ -146,8 +165,11 @@ public class MetadataServiceGatewayImpl implements MetadataServiceGateway { log.error("Failed to find table with id {}: service responded unsuccessful: {}", id, response.getStatusCode()); throw new MetadataServiceException("Failed to find table: service responded unsuccessful: " + response.getStatusCode()); } - if (!response.getHeaders().keySet().containsAll(List.of("X-Type", "X-Host", "X-Port", "X-Username", "X-Password", "X-Database", "X-Sidecar-Host", "X-Sidecar-Port"))) { + final List<String> expectedHeaders = List.of("X-Type", "X-Host", "X-Port", "X-Username", "X-Password", "X-Database", "X-Sidecar-Host", "X-Sidecar-Port"); + if (!response.getHeaders().keySet().containsAll(expectedHeaders)) { log.error("Failed to find all privileged table headers"); + log.debug("expected headers: {}", expectedHeaders); + log.debug("found headers: {}", response.getHeaders().keySet()); throw new MetadataServiceException("Failed to find all privileged table headers"); } if (response.getBody() == null) { @@ -184,8 +206,11 @@ public class MetadataServiceGatewayImpl implements MetadataServiceGateway { log.error("Failed to find view with id {}: service responded unsuccessful: {}", id, response.getStatusCode()); throw new MetadataServiceException("Failed to find view: service responded unsuccessful: " + response.getStatusCode()); } - if (!response.getHeaders().keySet().containsAll(List.of("X-Type", "X-Host", "X-Port", "X-Username", "X-Password", "X-Database"))) { + final List<String> expectedHeaders = List.of("X-Type", "X-Host", "X-Port", "X-Username", "X-Password", "X-Database"); + if (!response.getHeaders().keySet().containsAll(expectedHeaders)) { log.error("Failed to find all privileged view headers"); + log.debug("expected headers: {}", expectedHeaders); + log.debug("found headers: {}", response.getHeaders().keySet()); throw new MetadataServiceException("Failed to find all privileged view headers"); } if (response.getBody() == null) { @@ -226,6 +251,34 @@ public class MetadataServiceGatewayImpl implements MetadataServiceGateway { return response.getBody(); } + @Override + public UUID getSystemUserId() throws RemoteUnavailableException, UserNotFoundException, + MetadataServiceException { + final ResponseEntity<UserBriefDto[]> response; + try { + response = restTemplate.exchange("/api/user?username=" + gatewayConfig.getSystemUsername(), HttpMethod.GET, HttpEntity.EMPTY, UserBriefDto[].class); + } catch (ResourceAccessException | HttpServerErrorException e) { + log.error("Failed to find user with username {}: {}", gatewayConfig.getSystemUsername(), e.getMessage()); + throw new RemoteUnavailableException("Failed to find user with username " + gatewayConfig.getSystemUsername() + ": " + e.getMessage(), e); + } catch (HttpClientErrorException.NotFound e) { + log.error("Failed to find user with username {}: not found: {}", gatewayConfig.getSystemUsername(), e.getMessage()); + throw new UserNotFoundException("Failed to find user with username " + gatewayConfig.getSystemUsername() + ": " + e.getMessage(), e); + } + if (!response.getStatusCode().equals(HttpStatus.OK)) { + log.error("Failed to find user with username {}: service responded unsuccessful: {}", gatewayConfig.getSystemUsername(), response.getStatusCode()); + throw new MetadataServiceException("Failed to find user with username " + gatewayConfig.getSystemUsername() + ": service responded unsuccessful: " + response.getStatusCode()); + } + if (response.getBody() == null) { + log.error("Failed to find user with username {}: body is empty", gatewayConfig.getSystemUsername()); + throw new MetadataServiceException("Failed to find user with username " + gatewayConfig.getSystemUsername() + ": body is empty"); + } + if (response.getBody().length != 1) { + log.error("Failed to find system user: expected exactly one result but got {}", response.getBody().length); + throw new MetadataServiceException("Failed to find system user: expected exactly one result but got " + response.getBody().length); + } + return response.getBody()[0].getId(); + } + @Override public PrivilegedUserDto getPrivilegedUserById(UUID userId) throws RemoteUnavailableException, UserNotFoundException, MetadataServiceException { @@ -243,8 +296,11 @@ public class MetadataServiceGatewayImpl implements MetadataServiceGateway { log.error("Failed to find user with id {}: service responded unsuccessful: {}", userId, response.getStatusCode()); throw new MetadataServiceException("Failed to find user: service responded unsuccessful: " + response.getStatusCode()); } - if (!response.getHeaders().keySet().containsAll(List.of("X-Username", "X-Password"))) { + final List<String> expectedHeaders = List.of("X-Username", "X-Password"); + if (!response.getHeaders().keySet().containsAll(expectedHeaders)) { log.error("Failed to find all privileged user headers"); + log.debug("expected headers: {}", expectedHeaders); + log.debug("found headers: {}", response.getHeaders().keySet()); throw new MetadataServiceException("Failed to find all privileged user headers"); } if (response.getBody() == null) { diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/interceptor/KeycloakInterceptor.java b/dbrepo-data-service/services/src/main/java/at/tuwien/interceptor/KeycloakInterceptor.java deleted file mode 100644 index 78fb5adc61fd2420cfc62e72cb4aa4c700c3b82b..0000000000000000000000000000000000000000 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/interceptor/KeycloakInterceptor.java +++ /dev/null @@ -1,55 +0,0 @@ -package at.tuwien.interceptor; - -import at.tuwien.api.keycloak.TokenDto; -import lombok.extern.log4j.Log4j2; -import org.springframework.http.*; -import org.springframework.http.client.ClientHttpRequestExecution; -import org.springframework.http.client.ClientHttpRequestInterceptor; -import org.springframework.http.client.ClientHttpResponse; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; -import org.springframework.web.client.HttpServerErrorException; -import org.springframework.web.client.ResourceAccessException; -import org.springframework.web.client.RestTemplate; - -import java.io.IOException; - -@Log4j2 -public class KeycloakInterceptor implements ClientHttpRequestInterceptor { - - private final String adminUsername; - private final String adminPassword; - private final String keycloakEndpoint; - - public KeycloakInterceptor(String adminUsername, String adminPassword, String keycloakEndpoint) { - this.adminUsername = adminUsername; - this.adminPassword = adminPassword; - this.keycloakEndpoint = keycloakEndpoint; - } - - @Override - public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) - throws IOException { - final RestTemplate restTemplate = new RestTemplate(); - final HttpHeaders headers = new HttpHeaders(); - headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); - final MultiValueMap<String, String> payload = new LinkedMultiValueMap<>(); - payload.add("username", adminUsername); - payload.add("password", adminPassword); - payload.add("grant_type", "password"); - payload.add("client_id", "admin-cli"); - final ResponseEntity<TokenDto> response; - try { - response = restTemplate.exchange(keycloakEndpoint + "/realms/master/protocol/openid-connect/token", - HttpMethod.POST, new HttpEntity<>(payload, headers), TokenDto.class); - } catch (ResourceAccessException | HttpServerErrorException.ServiceUnavailable e) { - log.error("Failed to obtain admin token: {}", e.getMessage()); - return execution.execute(request, body); - } - if (response.getBody() == null) { - return execution.execute(request, body); - } - request.getHeaders().set("Authorization", "Bearer " + response.getBody().getAccessToken()); - return execution.execute(request, body); - } -} diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/DataMapper.java b/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/DataMapper.java index b34053ec88a47a1f02ab99048fffc7e7f0cf35dd..62b529976d029c0612e3849f032e0a1093270562 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/DataMapper.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/DataMapper.java @@ -1,6 +1,5 @@ package at.tuwien.mapper; -import at.tuwien.api.container.image.ImageDateDto; import at.tuwien.api.database.DatabaseDto; import at.tuwien.api.database.ViewColumnDto; import at.tuwien.api.database.ViewDto; @@ -26,7 +25,6 @@ import at.tuwien.config.QueryConfig; import at.tuwien.exception.QueryNotFoundException; import at.tuwien.exception.TableNotFoundException; import com.github.dockerjava.zerodep.shaded.org.apache.commons.codec.binary.Hex; -import com.google.common.hash.Hashing; import net.sf.jsqlparser.JSQLParserException; import net.sf.jsqlparser.parser.CCJSqlParserManager; import net.sf.jsqlparser.schema.Column; @@ -36,6 +34,7 @@ import org.jetbrains.annotations.NotNull; import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.mapstruct.Mappings; +import org.testcontainers.shaded.com.google.common.hash.Hashing; import org.testcontainers.shaded.org.apache.commons.io.FileUtils; import java.io.File; @@ -45,7 +44,6 @@ import java.io.StringReader; import java.math.BigInteger; import java.nio.charset.StandardCharsets; import java.sql.*; -import java.sql.Date; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.ZoneId; @@ -53,7 +51,6 @@ import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatterBuilder; import java.util.*; import java.util.stream.Collectors; -import java.util.stream.Stream; @Mapper(componentModel = "spring") public interface DataMapper { @@ -143,7 +140,6 @@ public interface DataMapper { default TableDto resultSetToTable(ResultSet resultSet, TableDto table, QueryConfig queryConfig) throws SQLException { final ColumnDto column = ColumnDto.builder() .ordinalPosition(resultSet.getInt(1) - 1) /* start at zero */ - .autoGenerated(resultSet.getString(2) != null && resultSet.getString(2).startsWith("nextval")) .isNullAllowed(resultSet.getString(3).equals("YES")) .columnType(ColumnTypeDto.valueOf(resultSet.getString(4).toUpperCase())) .d(resultSet.getString(7) != null ? resultSet.getLong(7) : null) @@ -177,19 +173,6 @@ public interface DataMapper { } else if (resultSet.getString(6) != null) { column.setSize(resultSet.getLong(6)); } - if (column.getColumnType().equals(ColumnTypeDto.TIMESTAMP) || column.getColumnType().equals(ColumnTypeDto.DATETIME)) { - column.setDateFormat(ImageDateDto.builder() - .id(queryConfig.getDefaultTimestampFormatId()) - .build()); - } else if (column.getColumnType().equals(ColumnTypeDto.DATE)) { - column.setDateFormat(ImageDateDto.builder() - .id(queryConfig.getDefaultDateFormatId()) - .build()); - } else if (column.getColumnType().equals(ColumnTypeDto.TIME)) { - column.setDateFormat(ImageDateDto.builder() - .id(queryConfig.getDefaultTimeFormatId()) - .build()); - } /* constraints */ if (resultSet.getString(9) != null && resultSet.getString(9).equals("PRI")) { table.getConstraints().getPrimaryKey().add(PrimaryKeyDto.builder() @@ -221,19 +204,6 @@ public interface DataMapper { } else if (resultSet.getString(6) != null) { column.setSize(resultSet.getLong(6)); } - if (column.getColumnType().equals(ColumnTypeDto.TIMESTAMP) || column.getColumnType().equals(ColumnTypeDto.DATETIME)) { - column.setDateFormat(ImageDateDto.builder() - .id(queryConfig.getDefaultTimestampFormatId()) - .build()); - } else if (column.getColumnType().equals(ColumnTypeDto.DATE)) { - column.setDateFormat(ImageDateDto.builder() - .id(queryConfig.getDefaultDateFormatId()) - .build()); - } else if (column.getColumnType().equals(ColumnTypeDto.TIME)) { - column.setDateFormat(ImageDateDto.builder() - .id(queryConfig.getDefaultTimeFormatId()) - .build()); - } view.getColumns() .add(column); log.trace("parsed view {}.{} column: {}", view.getDatabase().getInternalName(), view.getInternalName(), column.getInternalName()); @@ -562,10 +532,6 @@ public interface DataMapper { } switch (column.getColumnType()) { case DATE -> { - if (column.getDateFormat() == null) { - log.error("Missing date format for column {}", column.getId()); - throw new IllegalArgumentException("Missing date format"); - } final DateTimeFormatter formatter = new DateTimeFormatterBuilder() .parseCaseInsensitive() /* case insensitive to parse JAN and FEB */ .appendPattern("yyyy-MM-dd") @@ -575,10 +541,6 @@ public interface DataMapper { .toInstant(); } case TIMESTAMP, DATETIME -> { - if (column.getDateFormat() == null) { - log.error("Missing date format for column {}", column.getId()); - throw new IllegalArgumentException("Missing date format"); - } return Timestamp.valueOf(data.toString()) .toInstant(); } @@ -588,7 +550,7 @@ public interface DataMapper { case TEXT, CHAR, VARCHAR, TINYTEXT, MEDIUMTEXT, LONGTEXT, ENUM, SET -> { return String.valueOf(data); } - case BIGINT -> { + case BIGINT, SERIAL -> { return new BigInteger(String.valueOf(data)); } case INT, SMALLINT, MEDIUMINT, TINYINT -> { @@ -678,9 +640,9 @@ public interface DataMapper { ps.setNull(idx, Types.DATE); break; } - ps.setDate(idx, Date.valueOf(String.valueOf(value))); + ps.setString(idx, String.valueOf(value)); break; - case BIGINT: + case BIGINT, SERIAL: if (value == null) { ps.setNull(idx, Types.BIGINT); break; @@ -743,28 +705,7 @@ public interface DataMapper { } ps.setBoolean(idx, Boolean.parseBoolean(String.valueOf(value))); break; - case TIMESTAMP: - if (value == null) { - ps.setNull(idx, Types.TIMESTAMP); - break; - } - ps.setTimestamp(idx, Timestamp.valueOf(String.valueOf(value))); - break; - case DATETIME: - if (value == null) { - ps.setNull(idx, Types.TIMESTAMP); - break; - } - ps.setTimestamp(idx, Timestamp.valueOf(String.valueOf(value))); - break; - case TIME: - if (value == null) { - ps.setNull(idx, Types.TIME); - break; - } - ps.setTime(idx, Time.valueOf(String.valueOf(value))); - break; - case YEAR: + case TIME, DATETIME, TIMESTAMP, YEAR: if (value == null) { ps.setNull(idx, Types.TIME); break; diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/MariaDbMapper.java b/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/MariaDbMapper.java index 3e0bb2f01838560a5c49d05e8137b565914fdf85..bfca2d923fc550a6420f1140a9a9fe6d3aae7e59 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/MariaDbMapper.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/MariaDbMapper.java @@ -1,22 +1,27 @@ package at.tuwien.mapper; -import at.tuwien.api.database.query.ImportCsvDto; -import at.tuwien.api.database.table.*; -import at.tuwien.api.database.table.columns.*; +import at.tuwien.api.database.query.ImportDto; +import at.tuwien.api.database.table.TupleDeleteDto; +import at.tuwien.api.database.table.TupleDto; +import at.tuwien.api.database.table.TupleUpdateDto; +import at.tuwien.api.database.table.columns.ColumnCreateDto; +import at.tuwien.api.database.table.columns.ColumnDto; +import at.tuwien.api.database.table.columns.ColumnTypeDto; import at.tuwien.api.database.table.internal.PrivilegedTableDto; -import at.tuwien.exception.*; +import at.tuwien.exception.QueryMalformedException; +import at.tuwien.exception.TableMalformedException; import at.tuwien.utils.MariaDbUtil; import org.mapstruct.Mapper; import org.mapstruct.Named; -import java.io.*; -import java.math.BigInteger; -import java.sql.*; +import java.io.ByteArrayInputStream; +import java.io.InputStream; import java.sql.Date; +import java.sql.*; import java.text.Normalizer; -import java.time.*; +import java.time.Instant; +import java.time.ZoneId; import java.time.format.DateTimeFormatter; -import java.time.format.DateTimeFormatterBuilder; import java.util.*; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -293,6 +298,9 @@ public interface MariaDbMapper { .append(column.getInternalName()) .append("`) as std_dev FROM ") .append(table)); + if (statement.isEmpty()) { + return null; + } statement.append(";"); log.trace("mapped select column statistic statement: {}", statement); return statement.toString(); @@ -545,7 +553,7 @@ public interface MariaDbMapper { return statement.toString(); } - default String datasetToRawInsertQuery(String databaseName, PrivilegedTableDto table, ImportCsvDto data) { + default String datasetToRawInsertQuery(String databaseName, PrivilegedTableDto table, ImportDto data) { final StringBuilder statement = new StringBuilder("LOAD DATA INFILE '") .append(data.getLocation()) .append("' REPLACE INTO TABLE `") @@ -560,38 +568,17 @@ public interface MariaDbMapper { .append(data.getQuote()) .append("'"); } - statement.append(" LINES TERMINATED BY '") - .append(data.getLineTermination()) - .append("'") - .append(data.getSkipLines() != null ? (" IGNORE " + data.getSkipLines() + " LINES") : "") - .append(" ("); - final StringBuilder set = new StringBuilder(); - int[] idx = new int[]{0}; - table.getColumns() - .forEach(column -> { - if (column.getAutoGenerated()) { - log.trace("import column is auto generated, skip"); - return; - } - statement.append(idx[0] != 0 ? "," : ""); - /* format as variable */ - statement.append("@") - .append(column.getInternalName()); - if (column.getDateFormat() != null) { - /* reformat dates */ - columnToDateSet(data, column, set); - } else if (column.getColumnType().equals(ColumnTypeDto.BOOL)) { - /* reformat booleans */ - columnToBoolSet(data, column, set); - } else { - /* reformat others */ - columnToTextSet(data, column, set); - } - idx[0]++; - }); - statement.append(")") - .append(set.length() != 0 ? (" SET " + set) : "") - .append(";"); + if (data.getLineTermination() != null) { + statement.append(" LINES TERMINATED BY '") + .append(data.getLineTermination()) + .append("'"); + } + if (data.getSkipLines() != null) { + statement.append(" IGNORE ") + .append(data.getSkipLines()) + .append(" LINES"); + } + statement.append(";"); log.trace("mapped insert statement: {}", statement); return statement.toString(); } @@ -677,9 +664,6 @@ public interface MariaDbMapper { log.error("Failed to find table column {}", key); throw new IllegalArgumentException("Failed to find table column"); } - if (optional.get().getAutoGenerated()) { - return; - } statement.append(idx[0]++ == 0 ? "" : ", ") .append("`") .append(key) @@ -696,9 +680,6 @@ public interface MariaDbMapper { log.error("Failed to find table column {}", key); throw new IllegalArgumentException("Failed to find table column"); } - if (optional.get().getAutoGenerated()) { - return; - } statement.append(jdx[0]++ == 0 ? "" : ", ") .append("?"); }); @@ -707,125 +688,6 @@ public interface MariaDbMapper { return statement.toString(); } - default void columnToDateSet(ImportCsvDto data, ColumnDto column, StringBuilder set) { - log.trace("import column has date format, need to format it: {}", column.getDateFormat().getUnixFormat()); - set.append(!set.isEmpty() ? ", " : "") - .append("`") - .append(column.getInternalName()) - .append("` = STR_TO_DATE("); - if (data.getNullElement() != null) { - set.append("IF(STRCMP(@") - .append(column.getInternalName()) - .append(",'") - .append(data.getNullElement()) - .append("'), @") - .append(column.getInternalName()) - .append(", NULL), '") - .append(column.getDateFormat() - .getDatabaseFormat() - .replace('\'', '\\')) - .append("')"); - return; - } - set.append("@") - .append(column.getInternalName()) - .append(", '") - .append(column.getDateFormat() - .getDatabaseFormat() - .replace('\'', '\\')) - .append("')"); - } - - default void columnToBoolSet(ImportCsvDto data, ColumnDto column, StringBuilder set) { - set.append(!set.isEmpty() ? ", " : "") - .append("`") - .append(column.getInternalName()) - .append("` = "); - if (data.getNullElement() != null) { - set.append("IF(!STRCMP(@") - .append(column.getInternalName()) - .append(",'") - .append(data.getNullElement()) - .append("'),NULL,"); - columnToBoolSet2(data, column, set); - set.append(")"); - return; - } - columnToBoolSet2(data, column, set); - } - - default void columnToBoolSet2(ImportCsvDto data, ColumnDto column, StringBuilder set) { - if (data.getTrueElement() != null) { - set.append("IF(!STRCMP(@") - .append(column.getInternalName()) - .append(",'") - .append(data.getTrueElement()) - .append("'),TRUE,"); - if (data.getFalseElement() != null) { - log.trace("import has false element present (both true and false)"); - /* can map both true/false */ - set.append("IF(!STRCMP(@") - .append(column.getInternalName()) - .append(",'") - .append(data.getFalseElement()) - .append("'),FALSE,@") - .append(column.getInternalName()) - .append("))"); - } else { - /* can only map true */ - set.append("@") - .append(column.getInternalName()) - .append(")"); - } - return; - } - if (data.getFalseElement() != null) { - set.append("IF(!STRCMP(@") - .append(column.getInternalName()) - .append(",'") - .append(data.getFalseElement()) - .append("'),FALSE,"); - if (data.getTrueElement() != null) { - log.trace("import has true element present (both true and false)"); - /* can map both true/false */ - set.append("IF(!STRCMP(@") - .append(column.getInternalName()) - .append(",'") - .append(data.getTrueElement()) - .append("'),TRUE,@") - .append(column.getInternalName()) - .append("))"); - } else { - /* can only map true */ - set.append("@") - .append(column.getInternalName()) - .append(")"); - } - return; - } - set.append("@") - .append(column.getInternalName()); - } - - default void columnToTextSet(ImportCsvDto data, ColumnDto column, StringBuilder set) { - set.append(!set.isEmpty() ? ", " : "") - .append("`") - .append(column.getInternalName()) - .append("` = "); - if (data.getNullElement() != null) { - set.append("IF(STRCMP(@") - .append(column.getInternalName()) - .append(",'") - .append(data.getNullElement()) - .append("'), @") - .append(column.getInternalName()) - .append(", NULL)"); - return; - } - set.append("@") - .append(column.getInternalName()); - } - default void prepareStatementWithColumnTypeObject(PreparedStatement statement, ColumnTypeDto columnType, int idx, String columnName, Object value) throws SQLException { switch (columnType) { @@ -834,17 +696,8 @@ public interface MariaDbMapper { statement.setNull(idx, Types.BLOB); break; } - try { - final ByteArrayOutputStream boas = new ByteArrayOutputStream(); - try (ObjectOutputStream ois = new ObjectOutputStream(boas)) { - ois.writeObject(value); - statement.setBlob(idx, new ByteArrayInputStream(boas.toByteArray())); - } - - } catch (IOException e) { - log.error("Failed to set blob/tinyblob/mediumblob/longblob: {}", e.getMessage()); - throw new SQLException("Failed to set blob: " + e.getMessage(), e); - } + final byte[] data = (byte[]) value; + statement.setBlob(idx, new ByteArrayInputStream(data)); break; case TEXT, CHAR, VARCHAR, TINYTEXT, MEDIUMTEXT, LONGTEXT, ENUM, SET: if (value == null) { @@ -858,9 +711,9 @@ public interface MariaDbMapper { statement.setNull(idx, Types.DATE); break; } - statement.setDate(idx, Date.valueOf(String.valueOf(value))); + statement.setString(idx, String.valueOf(value)); break; - case BIGINT: + case BIGINT, SERIAL: if (value == null) { statement.setNull(idx, Types.BIGINT); break; @@ -872,21 +725,21 @@ public interface MariaDbMapper { statement.setNull(idx, Types.INTEGER); break; } - statement.setLong(idx, Long.parseLong(String.valueOf(value))); + statement.setLong(idx, Integer.parseInt(String.valueOf(value))); break; case TINYINT: if (value == null) { statement.setNull(idx, Types.TINYINT); break; } - statement.setLong(idx, Long.parseLong(String.valueOf(value))); + statement.setLong(idx, Integer.parseInt(String.valueOf(value))); break; case SMALLINT: if (value == null) { statement.setNull(idx, Types.SMALLINT); break; } - statement.setLong(idx, Long.parseLong(String.valueOf(value))); + statement.setInt(idx, Integer.parseInt(String.valueOf(value))); break; case DECIMAL: if (value == null) { @@ -928,16 +781,9 @@ public interface MariaDbMapper { statement.setNull(idx, Types.TIMESTAMP); break; } - statement.setTimestamp(idx, Timestamp.valueOf(String.valueOf(value))); - break; - case TIME: - if (value == null) { - statement.setNull(idx, Types.TIME); - break; - } - statement.setTime(idx, Time.valueOf(String.valueOf(value))); + statement.setString(idx, String.valueOf(value)); break; - case YEAR: + case TIME, YEAR: if (value == null) { statement.setNull(idx, Types.TIME); break; diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/QueueService.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/QueueService.java index 3a94045c9d209d57dc8bc9f5417a41980852fe6a..79a23932b5aee74da800c0b41023a7257fa4d32b 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/QueueService.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/QueueService.java @@ -12,6 +12,7 @@ public interface QueueService { * * @param table The table. * @param data The data. + * @throws SQLException The connection to the database could not be established. */ void insert(PrivilegedTableDto table, Map<String, Object> data) throws SQLException; } diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/StorageService.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/StorageService.java index e03878b8c19197e4347897c555a91d985c10fb72..c1f546ce4462d60eb08b1f34683efd7f05dca0f9 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/StorageService.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/StorageService.java @@ -15,6 +15,7 @@ public interface StorageService { * @param key The object key. * @return The input stream, if successful. * @throws StorageUnavailableException The object failed to be loaded from the Storage Service. + * @throws StorageNotFoundException The key was not found in the Storage Service. */ InputStream getObject(String bucket, String key) throws StorageUnavailableException, StorageNotFoundException; @@ -24,6 +25,7 @@ public interface StorageService { * @param key The object key. * @return The byte array. * @throws StorageUnavailableException The object failed to be loaded from the Storage Service. + * @throws StorageNotFoundException The key was not found in the Storage Service. */ byte[] getBytes(String key) throws StorageUnavailableException, StorageNotFoundException; @@ -34,6 +36,7 @@ public interface StorageService { * @param key The object key. * @return The byte array. * @throws StorageUnavailableException The object failed to be loaded from the Storage Service. + * @throws StorageNotFoundException The key was not found in the Storage Service. */ byte[] getBytes(String bucket, String key) throws StorageUnavailableException, StorageNotFoundException; @@ -43,6 +46,7 @@ public interface StorageService { * @param key The object key. * @return The export resource, if successful. * @throws StorageUnavailableException The object failed to be loaded from the Storage Service. + * @throws StorageNotFoundException The key was not found in the Storage Service. */ ExportResourceDto getResource(String key) throws StorageUnavailableException, StorageNotFoundException; @@ -53,6 +57,7 @@ public interface StorageService { * @param key The object key. * @return The export resource, if successful. * @throws StorageUnavailableException The object failed to be loaded from the Storage Service. + * @throws StorageNotFoundException The key was not found in the Storage Service. */ ExportResourceDto getResource(String bucket, String key) throws StorageUnavailableException, StorageNotFoundException; diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/SubsetService.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/SubsetService.java index 3c3ff101fead4b51caadc8c207848d2b962f98eb..56250a2917f2083d53bbeec51f6e3b1dae0e0cd1 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/SubsetService.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/SubsetService.java @@ -26,16 +26,60 @@ public interface SubsetService { void createQueryStore(PrivilegedContainerDto container, String databaseName) throws SQLException, QueryStoreCreateException; + /** + * Creates a subset from the given statement at given time in the given database. + * + * @param database The database. + * @param statement The subset statement. + * @param timestamp The timestamp as of which the data is queried. If smaller than <now>, historic data is queried. + * @param userId The user id of the creating user. + * @param page The page number. Optional but requires size to be set too. + * @param size The page size. Optional but requires page to be set too. + * @param sortDirection The sort direction. + * @param sortColumn The column that is sorted. + * @return The query result. + * @throws QueryStoreInsertException The query store refused to insert the query. + * @throws SQLException The connection to the database could not be established. + * @throws QueryNotFoundException The query was not found for re-execution. + * @throws TableMalformedException The table is malformed. + * @throws UserNotFoundException The user was not found. + * @throws NotAllowedException The operation is not allowed. + * @throws RemoteUnavailableException The privileged database information could not be found in the Metadata Service. + * @throws DatabaseNotFoundException The database was not found in the Metadata Service. + * @throws MetadataServiceException The Metadata Service responded unexpected. + */ QueryResultDto execute(PrivilegedDatabaseDto database, String statement, Instant timestamp, UUID userId, Long page, Long size, SortTypeDto sortDirection, String sortColumn) throws QueryStoreInsertException, SQLException, QueryNotFoundException, TableMalformedException, UserNotFoundException, NotAllowedException, RemoteUnavailableException, DatabaseNotFoundException, MetadataServiceException; + /** + * Re-executes the query of a given subset in the given database. + * + * @param database The database. + * @param query The subset. + * @param page The page number. Optional but requires size to be set too. + * @param size The page size. Optional but requires page to be set too. + * @param sortDirection The sort direction. + * @param sortColumn The column that is sorted. + * @return The query result. + * @throws TableMalformedException The table is malformed. + * @throws SQLException The connection to the database could not be established. + */ QueryResultDto reExecute(PrivilegedDatabaseDto database, QueryDto query, Long page, Long size, SortTypeDto sortDirection, String sortColumn) throws TableMalformedException, SQLException; + /** + * Counts the subset row count of a query of a given subset in the given database. + * + * @param database The database. + * @param query The subset. + * @return The row count. + * @throws TableMalformedException The table is malformed. + * @throws SQLException The connection to the database could not be established. + */ Long reExecuteCount(PrivilegedDatabaseDto database, QueryDto query) throws TableMalformedException, SQLException, QueryMalformedException; @@ -45,15 +89,45 @@ public interface SubsetService { * @param database The database. * @param filterPersisted Optional filter to only display persisted queries, or non-persisted queries. * @return The list of queries. + * @throws SQLException The connection to the database could not be established. + * @throws QueryNotFoundException The query was not found for re-execution. + * @throws RemoteUnavailableException The privileged database information could not be found in the Metadata Service. + * @throws DatabaseNotFoundException The database was not found in the Metadata Service. + * @throws MetadataServiceException The Metadata Service responded unexpected. */ List<QueryDto> findAll(PrivilegedDatabaseDto database, Boolean filterPersisted) throws SQLException, - QueryNotFoundException, NotAllowedException, RemoteUnavailableException, DatabaseNotFoundException, - MetadataServiceException; + QueryNotFoundException, RemoteUnavailableException, DatabaseNotFoundException, MetadataServiceException; + /** + * Exports a subset by re-executing the query in a given database with given timestamp to a given filename. + * + * @param database The database. + * @param query The query. + * @param timestamp The timestamp. + * @param filename The filename. + * @return The exported subset. + * @throws SQLException The connection to the database could not be established. + * @throws QueryMalformedException The mapped export query produced a database error. + * @throws SidecarExportException The sidecar of the given database failed to communicate. + * @throws StorageNotFoundException The exported subset was not found from the key provided by the sidecar in the Storage Service. + * @throws StorageUnavailableException The communication to the Storage Service failed. + * @throws RemoteUnavailableException The privileged database information could not be found in the Metadata Service. + */ ExportResourceDto export(PrivilegedDatabaseDto database, QueryDto query, Instant timestamp, String filename) throws SQLException, QueryMalformedException, SidecarExportException, StorageNotFoundException, - StorageUnavailableException, MetadataServiceException, RemoteUnavailableException; + StorageUnavailableException, RemoteUnavailableException; + /** + * Executes a subset query without saving it. + * + * @param database The database. + * @param statement The subset query. + * @param timestamp The timestamp. + * @return The row count. + * @throws SQLException The connection to the database could not be established. + * @throws QueryMalformedException The mapped query produced a database error. + * @throws TableMalformedException The database table is malformed. + */ Long executeCountNonPersistent(PrivilegedDatabaseDto database, String statement, Instant timestamp) throws SQLException, QueryMalformedException, TableMalformedException; @@ -63,11 +137,15 @@ public interface SubsetService { * @param database The database. * @param queryId The query id. * @return The query. - * @throws QueryNotFoundException The query store did not return a query + * @throws QueryNotFoundException The query store did not return a query. + * @throws SQLException The connection to the database could not be established. + * @throws RemoteUnavailableException The privileged database information could not be found in the Metadata Service. + * @throws UserNotFoundException The user that created the query was not found in the Metadata Service. + * @throws DatabaseNotFoundException The database metadata was not found in the Metadata Service. + * @throws MetadataServiceException Communication with the Metadata Service failed. */ QueryDto findById(PrivilegedDatabaseDto database, Long queryId) throws QueryNotFoundException, SQLException, - NotAllowedException, RemoteUnavailableException, UserNotFoundException, DatabaseNotFoundException, - MetadataServiceException; + RemoteUnavailableException, UserNotFoundException, DatabaseNotFoundException, MetadataServiceException; /** * Inserts a query and metadata to the query store of a given database id. @@ -75,7 +153,9 @@ public interface SubsetService { * @param database The database. * @param query The query statement. * @param userId The user id. - * @return The stored query on success + * @return The stored query id on success. + * @throws SQLException The connection to the database could not be established. + * @throws QueryStoreInsertException The query store failed to insert the query. */ Long storeQuery(PrivilegedDatabaseDto database, String query, Instant timestamp, UUID userId) throws SQLException, QueryStoreInsertException; @@ -83,15 +163,21 @@ public interface SubsetService { /** * Persists a query to be displayed in the frontend. * - * @param database The database id. + * @param database The database. * @param queryId The query id. * @param persist If true, the query is retained in the query store, ephemeral otherwise. + * @throws SQLException The connection to the database could not be established. + * @throws QueryStorePersistException The query store failed to persist/unpersist the query. */ void persist(PrivilegedDatabaseDto database, Long queryId, Boolean persist) throws SQLException, QueryStorePersistException; /** * Deletes the stale queries that have not been persisted within 24 hours. + * + * @param database The database. + * @throws SQLException The connection to the database could not be established. + * @throws QueryStoreGCException The query store failed to delete stale queries. */ void deleteStaleQueries(PrivilegedDatabaseDto database) throws SQLException, QueryStoreGCException; } diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/TableService.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/TableService.java index 765a3b7e2e630b70b4e52d99aaddecd8559754a3..c93186f451c5b41d2c55924ce685d578b40bfbde 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/TableService.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/TableService.java @@ -2,7 +2,7 @@ package at.tuwien.service; import at.tuwien.ExportResourceDto; import at.tuwien.api.database.internal.PrivilegedDatabaseDto; -import at.tuwien.api.database.query.ImportCsvDto; +import at.tuwien.api.database.query.ImportDto; import at.tuwien.api.database.query.QueryResultDto; import at.tuwien.api.database.table.*; import at.tuwien.api.database.table.internal.PrivilegedTableDto; @@ -104,18 +104,66 @@ public interface TableService { Long getCount(PrivilegedTableDto table, Instant timestamp) throws SQLException, QueryMalformedException; - void importDataset(PrivilegedTableDto table, ImportCsvDto data) throws SidecarImportException, + /** + * Imports a dataset by metadata into the sidecar of the target database by given table. + * @param table The table. + * @param data The dataset metadata. + * @throws SidecarImportException The sidecar of the target database failed to import the dataset. + * @throws StorageNotFoundException The storage service was not able to find the dataset for import. + * @throws SQLException Failed to parse SQL query, contains invalid syntax. + * @throws QueryMalformedException The import query is malformed, likely due to a bug in the application. + * @throws RemoteUnavailableException Failed to establish connection to the sidecar. + */ + void importDataset(PrivilegedTableDto table, ImportDto data) throws SidecarImportException, StorageNotFoundException, SQLException, QueryMalformedException, RemoteUnavailableException; + /** + * Imports a dataset by metadata into the sidecar of the target database by given table. + * @param table The table. + * @param data The dataset metadata. + * @throws SQLException Failed to parse SQL query, contains invalid syntax. + * @throws TableMalformedException The tuple is malformed and does not fit the table schema. + * @throws QueryMalformedException The delete query is malformed, likely due to a bug in the application. + */ void deleteTuple(PrivilegedTableDto table, TupleDeleteDto data) throws SQLException, TableMalformedException, QueryMalformedException; + /** + * Creates a tuple in a table. + * @param table The table. + * @param data The tuple. + * @throws SQLException Failed to parse SQL query, contains invalid syntax. + * @throws QueryMalformedException The create query is malformed, likely due to a bug in the application. + * @throws TableMalformedException The tuple is malformed and does not fit the table schema. + * @throws StorageUnavailableException Failed to establish a connection with the Storage Service. + * @throws StorageNotFoundException The storage service was not able to find the dataset for import. + */ void createTuple(PrivilegedTableDto table, TupleDto data) throws SQLException, QueryMalformedException, TableMalformedException, StorageUnavailableException, StorageNotFoundException; + /** + * Updates a tuple in a table. + * @param table The table. + * @param data The tuple. + * @throws SQLException Failed to parse SQL query, contains invalid syntax. + * @throws QueryMalformedException The update query is malformed, likely due to a bug in the application. + * @throws TableMalformedException The tuple is malformed and does not fit the table schema. + */ void updateTuple(PrivilegedTableDto table, TupleUpdateDto data) throws SQLException, QueryMalformedException, TableMalformedException; + /** + * Exports a table at given system-versioning time. + * @param table The table. + * @param timestamp The system-versioning time. + * @return The exported resource. + * @throws SQLException Failed to parse SQL query, contains invalid syntax. + * @throws SidecarExportException The sidecar of the target database failed to export the dataset. + * @throws StorageNotFoundException The storage service was not able to find the dataset for export. + * @throws StorageUnavailableException Failed to establish a connection with the Storage Service. + * @throws QueryMalformedException The export query is malformed, likely due to a bug in the application. + * @throws RemoteUnavailableException Failed to establish connection to the sidecar. + */ ExportResourceDto exportDataset(PrivilegedTableDto table, Instant timestamp) throws SQLException, SidecarExportException, StorageNotFoundException, StorageUnavailableException, QueryMalformedException, RemoteUnavailableException; diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/ViewService.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/ViewService.java index f4bef4f067706688dc30234a3a375678214cdb8f..9151f868de9f271f9c73cc8f7da4fccf168b668d 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/ViewService.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/ViewService.java @@ -15,12 +15,12 @@ import java.util.List; public interface ViewService { /** - * - * @param database + * Gets the metadata schema for a given database. + * @param database The database. * @return The list of view metadata. - * @throws SQLException - * @throws DatabaseMalformedException - * @throws ViewNotFoundException + * @throws SQLException The connection to the data database was unsuccessful. + * @throws DatabaseMalformedException The columns that are referenced in the views are unknown to the Metadata Database. Call {@link TableService#getSchemas(PrivilegedDatabaseDto)} beforehand. + * @throws ViewNotFoundException The view with given name was not found. */ List<ViewDto> getSchemas(PrivilegedDatabaseDto database) throws SQLException, DatabaseMalformedException, ViewNotFoundException; @@ -50,11 +50,35 @@ public interface ViewService { QueryResultDto data(PrivilegedViewDto view, Instant timestamp, Long page, Long size) throws SQLException, ViewMalformedException; + /** + * Deletes a view. + * @param view The view. + * @throws SQLException The connection to the data database was unsuccessful. + * @throws ViewMalformedException The query is malformed and was rejected by the data database. + */ void delete(PrivilegedViewDto view) throws SQLException, ViewMalformedException; + /** + * Counts tuples in a view at system-versioned timestamp. + * @param view The view. + * @param timestamp The system-versioned timestamp. + * @return The number of tuples. + * @throws SQLException The connection to the data database was unsuccessful. + * @throws QueryMalformedException The query is malformed and was rejected by the data database. + */ Long count(PrivilegedViewDto view, Instant timestamp) throws SQLException, QueryMalformedException; - ExportResourceDto exportDataset(PrivilegedDatabaseDto database, ViewDto view, Instant timestamp) - throws SQLException, QueryMalformedException, SidecarExportException, StorageNotFoundException, - StorageUnavailableException, RemoteUnavailableException; + /** + * Exports view data into a dataset. + * @param view The view. + * @return The dataset. + * @throws SQLException The connection to the data database was unsuccessful. + * @throws QueryMalformedException The query is malformed and was rejected by the data database. + * @throws SidecarExportException The sidecar of the target database failed to export the dataset. + * @throws RemoteUnavailableException Failed to establish connection to the sidecar. + * @throws StorageNotFoundException The storage service was not able to find the dataset for export. + * @throws StorageUnavailableException Failed to establish a connection with the Storage Service. + */ + ExportResourceDto exportDataset(PrivilegedViewDto view) throws SQLException, QueryMalformedException, + SidecarExportException, RemoteUnavailableException, StorageNotFoundException, StorageUnavailableException; } diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/QueueServiceRabbitMqImpl.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/QueueServiceRabbitMqImpl.java index 0b1dc7caa1cd7f530d6d8590ffb09225e8048ff4..797de6567445ea6acdc45c656d8910f68084ac8b 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/QueueServiceRabbitMqImpl.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/QueueServiceRabbitMqImpl.java @@ -6,6 +6,7 @@ import at.tuwien.mapper.DataMapper; import at.tuwien.mapper.MetadataMapper; import at.tuwien.service.QueueService; import com.mchange.v2.c3p0.ComboPooledDataSource; +import io.micrometer.core.instrument.Counter; import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -20,11 +21,14 @@ import java.util.Optional; @Service public class QueueServiceRabbitMqImpl extends HibernateConnector implements QueueService { + private final Counter amqpDataAccessCounter; private final DataMapper dataMapper; private final MetadataMapper metadataMapper; @Autowired - public QueueServiceRabbitMqImpl(DataMapper dataMapper, MetadataMapper metadataMapper) { + public QueueServiceRabbitMqImpl(Counter amqpDataAccessCounter, DataMapper dataMapper, + MetadataMapper metadataMapper) { + this.amqpDataAccessCounter = amqpDataAccessCounter; this.dataMapper = dataMapper; this.metadataMapper = metadataMapper; } @@ -50,6 +54,7 @@ public class QueueServiceRabbitMqImpl extends HibernateConnector implements Queu preparedStatement.executeUpdate(); log.debug("executed statement in {} ms", System.currentTimeMillis() - start); log.trace("successfully inserted tuple"); + amqpDataAccessCounter.increment(); } finally { dataSource.close(); } diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/SubsetServiceMariaDbImpl.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/SubsetServiceMariaDbImpl.java index 53d93d35dfaa11d4ec40ef5e00b73050ebea91c5..8bfdc0089a9d31ce9faa8af40be151eb1044532f 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/SubsetServiceMariaDbImpl.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/SubsetServiceMariaDbImpl.java @@ -17,18 +17,18 @@ import at.tuwien.gateway.MetadataServiceGateway; import at.tuwien.mapper.DataMapper; import at.tuwien.mapper.MariaDbMapper; import at.tuwien.mapper.MetadataMapper; -import at.tuwien.service.SubsetService; import at.tuwien.service.StorageService; -import com.google.common.hash.Hashing; +import at.tuwien.service.SubsetService; import com.mchange.v2.c3p0.ComboPooledDataSource; +import io.micrometer.core.instrument.Counter; import lombok.extern.log4j.Log4j2; import net.sf.jsqlparser.JSQLParserException; import org.apache.commons.lang3.RandomUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.testcontainers.shaded.com.google.common.hash.Hashing; import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; import java.sql.*; import java.time.Instant; import java.util.LinkedList; @@ -39,6 +39,7 @@ import java.util.UUID; @Service public class SubsetServiceMariaDbImpl extends HibernateConnector implements SubsetService { + private final Counter httpDataAccessCounter; private final S3Config s3Config; private final DataMapper dataMapper; private final MariaDbMapper mariaDbMapper; @@ -48,10 +49,11 @@ public class SubsetServiceMariaDbImpl extends HibernateConnector implements Subs private final DataDatabaseSidecarGateway dataDatabaseSidecarGateway; @Autowired - public SubsetServiceMariaDbImpl(S3Config s3Config, DataMapper dataMapper, MariaDbMapper mariaDbMapper, - MetadataMapper metadataMapper, StorageService storageService, - MetadataServiceGateway metadataServiceGateway, + public SubsetServiceMariaDbImpl(Counter httpDataAccessCounter, S3Config s3Config, DataMapper dataMapper, + MariaDbMapper mariaDbMapper, MetadataMapper metadataMapper, + StorageService storageService, MetadataServiceGateway metadataServiceGateway, DataDatabaseSidecarGateway dataDatabaseSidecarGateway) { + this.httpDataAccessCounter = httpDataAccessCounter; this.s3Config = s3Config; this.dataMapper = dataMapper; this.mariaDbMapper = mariaDbMapper; @@ -107,6 +109,7 @@ public class SubsetServiceMariaDbImpl extends HibernateConnector implements Subs MetadataServiceException { final Long queryId = storeQuery(database, statement, timestamp, userId); final QueryDto query = findById(database, queryId); + httpDataAccessCounter.increment(); return reExecute(database, query, page, size, sortDirection, sortColumn); } @@ -201,6 +204,7 @@ public class SubsetServiceMariaDbImpl extends HibernateConnector implements Subs dataSource.close(); } dataDatabaseSidecarGateway.exportFile(database.getContainer().getSidecarHost(), database.getContainer().getSidecarPort(), filename); + httpDataAccessCounter.increment(); return storageService.getResource(filename); } @@ -213,6 +217,7 @@ public class SubsetServiceMariaDbImpl extends HibernateConnector implements Subs final PreparedStatement preparedStatement = connection.prepareStatement(statement); final ResultSet resultSet = preparedStatement.executeQuery(); log.debug("executed statement in {} ms", System.currentTimeMillis() - start); + httpDataAccessCounter.increment(); return dataMapper.resultListToQueryResultDto(columns, resultSet); } catch (SQLException e) { log.error("Failed to execute and map time-versioned query: {}", e.getMessage()); @@ -232,6 +237,7 @@ public class SubsetServiceMariaDbImpl extends HibernateConnector implements Subs final ResultSet resultSet = connection.prepareStatement(mariaDbMapper.countRawSelectQuery(statement, timestamp)) .executeQuery(); log.debug("executed statement in {} ms", System.currentTimeMillis() - start); + httpDataAccessCounter.increment(); return mariaDbMapper.resultSetToNumber(resultSet); } catch (SQLException e) { log.error("Failed to map object: {}", e.getMessage()); @@ -281,7 +287,11 @@ public class SubsetServiceMariaDbImpl extends HibernateConnector implements Subs /* insert query into query store */ final long start = System.currentTimeMillis(); final CallableStatement callableStatement = connection.prepareCall(mariaDbMapper.queryStoreStoreQueryRawQuery()); - callableStatement.setString(1, String.valueOf(userId)); + if (userId != null) { + callableStatement.setString(1, String.valueOf(userId)); + } else { + callableStatement.setNull(1, Types.VARCHAR); + } callableStatement.setString(2, query); callableStatement.setTimestamp(3, Timestamp.from(timestamp)); callableStatement.registerOutParameter(4, Types.BIGINT); diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/TableServiceMariaDbImpl.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/TableServiceMariaDbImpl.java index 97778e9e11679bc349ef6037fe8c7a9150cf530a..3ab02bbb016ff28469301a699f2ebd65bfd76f6c 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/TableServiceMariaDbImpl.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/TableServiceMariaDbImpl.java @@ -2,7 +2,7 @@ package at.tuwien.service.impl; import at.tuwien.ExportResourceDto; import at.tuwien.api.database.internal.PrivilegedDatabaseDto; -import at.tuwien.api.database.query.ImportCsvDto; +import at.tuwien.api.database.query.ImportDto; import at.tuwien.api.database.query.QueryResultDto; import at.tuwien.api.database.table.*; import at.tuwien.api.database.table.columns.ColumnDto; @@ -20,6 +20,7 @@ import at.tuwien.service.StorageService; import at.tuwien.service.TableService; import at.tuwien.utils.MariaDbUtil; import com.mchange.v2.c3p0.ComboPooledDataSource; +import io.micrometer.core.instrument.Counter; import lombok.extern.log4j.Log4j2; import org.apache.commons.lang3.RandomStringUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -34,6 +35,7 @@ import java.util.*; @Service public class TableServiceMariaDbImpl extends HibernateConnector implements TableService { + private final Counter httpDataAccessCounter; private final S3Config s3Config; private final DataMapper dataMapper; private final MariaDbMapper mariaDbMapper; @@ -42,9 +44,11 @@ public class TableServiceMariaDbImpl extends HibernateConnector implements Table private final DataDatabaseSidecarGateway dataDatabaseSidecarGateway; @Autowired - public TableServiceMariaDbImpl(S3Config s3Config, DataMapper dataMapper, MariaDbMapper mariaDbMapper, - SchemaService schemaService, StorageService storageService, + public TableServiceMariaDbImpl(Counter httpDataAccessCounter, S3Config s3Config, DataMapper dataMapper, + MariaDbMapper mariaDbMapper, SchemaService schemaService, + StorageService storageService, DataDatabaseSidecarGateway dataDatabaseSidecarGateway) { + this.httpDataAccessCounter = httpDataAccessCounter; this.s3Config = s3Config; this.dataMapper = dataMapper; this.mariaDbMapper = mariaDbMapper; @@ -96,15 +100,28 @@ public class TableServiceMariaDbImpl extends HibernateConnector implements Table try { /* obtain statistic */ final long start = System.currentTimeMillis(); - final ResultSet resultSet = connection.prepareStatement(mariaDbMapper.tableColumnStatisticsSelectRawQuery(table.getColumns(), table.getInternalName())) - .executeQuery(); - log.debug("executed statement in {} ms", System.currentTimeMillis() - start); - statistic = dataMapper.resultSetToTableStatistic(resultSet); - final TableDto tmpTable = schemaService.inspectTable(table.getDatabase(), table.getInternalName()); - statistic.setAvgRowLength(tmpTable.getAvgRowLength()); - statistic.setDataLength(tmpTable.getDataLength()); - statistic.setMaxDataLength(tmpTable.getMaxDataLength()); - statistic.setRows(tmpTable.getNumRows()); + final String query = mariaDbMapper.tableColumnStatisticsSelectRawQuery(table.getColumns(), table.getInternalName()); + if (query == null) { + log.debug("table {}.{} does not have columns that can be analysed for statistical properties (i.e. no numeric columns)", table.getDatabase().getInternalName(), table.getInternalName()); + statistic = null; + } else { + final ResultSet resultSet = connection.prepareStatement(query) + .executeQuery(); + log.debug("executed statement in {} ms", System.currentTimeMillis() - start); + statistic = dataMapper.resultSetToTableStatistic(resultSet); + final TableDto tmpTable = schemaService.inspectTable(table.getDatabase(), table.getInternalName()); + statistic.setAvgRowLength(tmpTable.getAvgRowLength()); + statistic.setDataLength(tmpTable.getDataLength()); + statistic.setMaxDataLength(tmpTable.getMaxDataLength()); + statistic.setRows(tmpTable.getNumRows()); + /* add to statistic dto */ + table.getColumns() + .stream() + .filter(column -> !MariaDbUtil.numericDataTypes.contains(column.getColumnType())) + .forEach(column -> statistic.getColumns().put(column.getInternalName(), new ColumnStatisticDto())); + log.info("Obtained statistics for the table and {} column(s)", statistic.getColumns().size()); + log.trace("obtained statistics: {}", statistic); + } } catch (SQLException e) { connection.rollback(); log.error("Failed to obtain column statistics: {}", e.getMessage()); @@ -112,12 +129,6 @@ public class TableServiceMariaDbImpl extends HibernateConnector implements Table } finally { dataSource.close(); } - table.getColumns() - .stream() - .filter(column -> !MariaDbUtil.numericDataTypes.contains(column.getColumnType())) - .forEach(column -> statistic.getColumns().put(column.getInternalName(), new ColumnStatisticDto())); - log.info("Obtained statistics for the table and {} column(s)", statistic.getColumns().size()); - log.trace("obtained statistics: {}", statistic); return statistic; } @@ -196,6 +207,7 @@ public class TableServiceMariaDbImpl extends HibernateConnector implements Table connection.commit(); queryResult = dataMapper.resultListToQueryResultDto(table.getColumns(), resultSet); log.debug("mapped result in {} ms", System.currentTimeMillis() - start); + httpDataAccessCounter.increment(); } catch (SQLException e) { connection.rollback(); log.error("Failed to find data from table {}.{}: {}", table.getDatabase().getInternalName(), table.getInternalName(), e.getMessage()); @@ -261,7 +273,7 @@ public class TableServiceMariaDbImpl extends HibernateConnector implements Table } @Override - public void importDataset(PrivilegedTableDto table, ImportCsvDto data) throws StorageNotFoundException, + public void importDataset(PrivilegedTableDto table, ImportDto data) throws StorageNotFoundException, SQLException, QueryMalformedException, RemoteUnavailableException, SidecarImportException { /* import .csv from blob storage to sidecar */ dataDatabaseSidecarGateway.importFile(table.getDatabase().getContainer().getSidecarHost(), table.getDatabase().getContainer().getSidecarPort(), data.getLocation()); @@ -431,6 +443,7 @@ public class TableServiceMariaDbImpl extends HibernateConnector implements Table dataSource.close(); } dataDatabaseSidecarGateway.exportFile(table.getDatabase().getContainer().getSidecarHost(), table.getDatabase().getContainer().getSidecarPort(), fileName); + httpDataAccessCounter.increment(); return storageService.getResource(fileName); } diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/ViewServiceMariaDbImpl.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/ViewServiceMariaDbImpl.java index 06cf42ae6ed0b49f56f63648cd3286b4226f727a..366cfa5faf5fabe34210b880d3fdca3659267a3a 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/ViewServiceMariaDbImpl.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/ViewServiceMariaDbImpl.java @@ -19,6 +19,7 @@ import at.tuwien.service.StorageService; import at.tuwien.service.ViewService; import com.google.common.hash.Hashing; import com.mchange.v2.c3p0.ComboPooledDataSource; +import io.micrometer.core.instrument.Counter; import lombok.extern.log4j.Log4j2; import org.apache.commons.lang3.RandomStringUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -38,6 +39,7 @@ import java.util.List; @Service public class ViewServiceMariaDbImpl extends HibernateConnector implements ViewService { + private final Counter httpDataAccessCounter; private final S3Config s3Config; private final DataMapper dataMapper; private final QueryConfig queryConfig; @@ -48,10 +50,11 @@ public class ViewServiceMariaDbImpl extends HibernateConnector implements ViewSe private final DataDatabaseSidecarGateway dataDatabaseSidecarGateway; @Autowired - public ViewServiceMariaDbImpl(S3Config s3Config, DataMapper dataMapper, QueryConfig queryConfig, - MariaDbMapper mariaDbMapper, SchemaService schemaService, + public ViewServiceMariaDbImpl(Counter httpDataAccessCounter, S3Config s3Config, DataMapper dataMapper, + QueryConfig queryConfig, MariaDbMapper mariaDbMapper, SchemaService schemaService, StorageService storageService, MetadataMapper metadataMapper, DataDatabaseSidecarGateway dataDatabaseSidecarGateway) { + this.httpDataAccessCounter = httpDataAccessCounter; this.s3Config = s3Config; this.dataMapper = dataMapper; this.queryConfig = queryConfig; @@ -165,6 +168,7 @@ public class ViewServiceMariaDbImpl extends HibernateConnector implements ViewSe queryResult = dataMapper.resultListToQueryResultDto(mappedColumns, resultSet); queryResult.setId(view.getId()); connection.commit(); + httpDataAccessCounter.increment(); } catch (SQLException e) { log.error("Failed to map object: {}", e.getMessage()); throw new ViewMalformedException("Failed to map object: " + e.getMessage(), e); @@ -224,12 +228,11 @@ public class ViewServiceMariaDbImpl extends HibernateConnector implements ViewSe } @Override - public ExportResourceDto exportDataset(PrivilegedDatabaseDto database, ViewDto view, Instant timestamp) - throws SQLException, QueryMalformedException, StorageNotFoundException, StorageUnavailableException, - RemoteUnavailableException, SidecarExportException { + public ExportResourceDto exportDataset(PrivilegedViewDto view) throws SQLException, QueryMalformedException, + SidecarExportException, RemoteUnavailableException, StorageNotFoundException, StorageUnavailableException { final String fileName = RandomStringUtils.randomAlphabetic(40) + ".csv"; final String filePath = s3Config.getS3FilePath() + File.separator + fileName; - final ComboPooledDataSource dataSource = getPrivilegedDataSource(database); + final ComboPooledDataSource dataSource = getPrivilegedDataSource(view.getDatabase()); final Connection connection = dataSource.getConnection(); try { /* export to data database sidecar */ @@ -238,8 +241,8 @@ public class ViewServiceMariaDbImpl extends HibernateConnector implements ViewSe .map(metadataMapper::viewColumnDtoToColumnDto) .toList(); final long start = System.currentTimeMillis(); - connection.prepareStatement(mariaDbMapper.tableOrViewToRawExportQuery(database.getInternalName(), - view.getInternalName(), columns, timestamp, filePath)) + connection.prepareStatement(mariaDbMapper.tableOrViewToRawExportQuery(view.getDatabase().getInternalName(), + view.getInternalName(), columns, null, filePath)) .executeUpdate(); log.debug("executed statement in {} ms", System.currentTimeMillis() - start); connection.commit(); @@ -250,8 +253,9 @@ public class ViewServiceMariaDbImpl extends HibernateConnector implements ViewSe } finally { dataSource.close(); } - dataDatabaseSidecarGateway.exportFile(database.getContainer().getSidecarHost(), - database.getContainer().getSidecarPort(), fileName); + dataDatabaseSidecarGateway.exportFile(view.getDatabase().getContainer().getSidecarHost(), + view.getDatabase().getContainer().getSidecarPort(), fileName); + httpDataAccessCounter.increment(); return storageService.getResource(fileName); } diff --git a/dbrepo-gateway-service/dbrepo.conf b/dbrepo-gateway-service/dbrepo.conf index de8eaa417bbe422999436e83dc24f8fb66f9b1d5..6d3dce2b9e38b52d607cf3af1246c27e6b2e09bf 100644 --- a/dbrepo-gateway-service/dbrepo.conf +++ b/dbrepo-gateway-service/dbrepo.conf @@ -1,10 +1,12 @@ -client_max_body_size 2G; +# This is required to proxy Grafana Live WebSocket connections. +map $http_upgrade $connection_upgrade { + default upgrade; + '' close; +} -resolver 127.0.0.11 valid=30s; # docker dns +client_max_body_size 20G; -upstream auth { - server auth-service:8080; -} +resolver 127.0.0.11 valid=30s; # docker dns upstream broker { server broker-service:15672; @@ -38,13 +40,8 @@ server { listen 80 default_server; server_name _; - location /admin/broker { - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_pass http://broker; - proxy_read_timeout 90; + location = /basic_status { + stub_status; } location /api/search { @@ -57,7 +54,7 @@ server { } location /api/broker { - rewrite /api/broker/(.*) /admin/broker/api/$1 break; + rewrite /api/broker/(.*) /api/$1 break; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; @@ -91,16 +88,6 @@ server { proxy_read_timeout 90; } - location /api/auth { - rewrite /api/auth/(.*) /$1 break; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_pass http://auth; - proxy_read_timeout 90; - } - location ~ /api/database/([0-9]+)/table/([0-9]+)/(data|history|export|statistic) { proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; @@ -110,7 +97,7 @@ server { proxy_read_timeout 90; } - location ~ /api/database/([0-9]+)/view/([0-9]+)/data { + location ~ /api/database/([0-9]+)/view/([0-9]+)/(data|export) { proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; diff --git a/dbrepo-metadata-db/1_setup-schema.sql b/dbrepo-metadata-db/1_setup-schema.sql index 9213b8ea884924b5748553428238515033056b74..042f88f32e1e95d0ec295f92d0f6cc3c72381124 100644 --- a/dbrepo-metadata-db/1_setup-schema.sql +++ b/dbrepo-metadata-db/1_setup-schema.sql @@ -19,7 +19,7 @@ CREATE TABLE IF NOT EXISTS `mdb_users` CREATE TABLE IF NOT EXISTS `mdb_images` ( - id bigint NOT NULL AUTO_INCREMENT, + id SERIAL, registry character varying(255) NOT NULL DEFAULT 'docker.io', name character varying(255) NOT NULL, version character varying(255) NOT NULL, @@ -27,29 +27,17 @@ CREATE TABLE IF NOT EXISTS `mdb_images` dialect character varying(255) NOT NULL, driver_class character varying(255) NOT NULL, jdbc_method character varying(255) NOT NULL, + is_default BOOLEAN NOT NULL DEFAULT FALSE, created timestamp NOT NULL DEFAULT NOW(), last_modified timestamp, PRIMARY KEY (id), - UNIQUE (name, version) -) WITH SYSTEM VERSIONING; - -CREATE TABLE IF NOT EXISTS `mdb_images_date` -( - id bigint NOT NULL AUTO_INCREMENT, - iid bigint NOT NULL, - database_format character varying(255) NOT NULL, - unix_format character varying(255) NOT NULL, - example character varying(255) NOT NULL, - has_time boolean NOT NULL, - created_at timestamp NOT NULL DEFAULT NOW(), - PRIMARY KEY (id), - FOREIGN KEY (iid) REFERENCES mdb_images (id), - UNIQUE (database_format, unix_format, example) + UNIQUE (name, version), + UNIQUE (is_default) ) WITH SYSTEM VERSIONING; CREATE TABLE IF NOT EXISTS `mdb_containers` ( - id bigint NOT NULL AUTO_INCREMENT, + id SERIAL, internal_name character varying(255) NOT NULL, name character varying(255) NOT NULL, host character varying(255) NOT NULL, @@ -64,13 +52,13 @@ CREATE TABLE IF NOT EXISTS `mdb_containers` last_modified timestamp, privileged_username character varying(255) NOT NULL, privileged_password character varying(255) NOT NULL, - PRIMARY KEY (id), - FOREIGN KEY (image_id) REFERENCES mdb_images (id) + quota integer NOT NULL DEFAULT 50, + PRIMARY KEY (id) ) WITH SYSTEM VERSIONING; CREATE TABLE IF NOT EXISTS `mdb_data` ( - ID bigint NOT NULL AUTO_INCREMENT, + ID SERIAL, PROVENANCE text, FileEncoding text, FileType character varying(100), @@ -90,8 +78,8 @@ CREATE TABLE IF NOT EXISTS `mdb_licenses` CREATE TABLE IF NOT EXISTS `mdb_databases` ( - id bigint NOT NULL AUTO_INCREMENT, - cid bigint NOT NULL, + id SERIAL, + cid BIGINT UNSIGNED NOT NULL, name character varying(255) NOT NULL, internal_name character varying(255) NOT NULL, exchange_name character varying(255) NOT NULL, @@ -105,7 +93,7 @@ CREATE TABLE IF NOT EXISTS `mdb_databases` created timestamp NOT NULL DEFAULT NOW(), last_modified timestamp, PRIMARY KEY (id), - FOREIGN KEY (cid) REFERENCES mdb_containers (id) /* currently we only support one-to-one */, + FOREIGN KEY (cid) REFERENCES mdb_containers (id), FOREIGN KEY (created_by) REFERENCES mdb_users (id), FOREIGN KEY (owned_by) REFERENCES mdb_users (id), FOREIGN KEY (contact_person) REFERENCES mdb_users (id) @@ -120,8 +108,8 @@ CREATE TABLE IF NOT EXISTS `mdb_databases_subjects` CREATE TABLE IF NOT EXISTS `mdb_tables` ( - ID bigint NOT NULL AUTO_INCREMENT, - tDBID bigint NOT NULL, + ID SERIAL, + tDBID BIGINT UNSIGNED NOT NULL, tName VARCHAR(64) NOT NULL, internal_name VARCHAR(64) NOT NULL, queue_name VARCHAR(255) NOT NULL, @@ -152,35 +140,34 @@ CREATE TABLE IF NOT EXISTS `mdb_tables` CREATE TABLE IF NOT EXISTS `mdb_columns` ( - ID BIGINT NOT NULL AUTO_INCREMENT, - tID BIGINT NOT NULL, - dfID BIGINT, + ID SERIAL, + tID BIGINT UNSIGNED NOT NULL, cName VARCHAR(64), - internal_name VARCHAR(64) NOT NULL, - Datatype ENUM ('CHAR','VARCHAR','BINARY','VARBINARY','TINYBLOB','TINYTEXT','TEXT','BLOB','MEDIUMTEXT','MEDIUMBLOB','LONGTEXT','LONGBLOB','ENUM','SET','BIT','TINYINT','BOOL','SMALLINT','MEDIUMINT','INT','BIGINT','FLOAT','DOUBLE','DECIMAL','DATE','DATETIME','TIMESTAMP','TIME','YEAR'), - length BIGINT NULL, - ordinal_position INTEGER NOT NULL, - index_length BIGINT NULL, + internal_name VARCHAR(64) NOT NULL, + Datatype ENUM ('CHAR','VARCHAR','BINARY','VARBINARY','TINYBLOB','TINYTEXT','TEXT','BLOB','MEDIUMTEXT','MEDIUMBLOB','LONGTEXT','LONGBLOB','ENUM','SET','SERIAL','BIT','TINYINT','BOOL','SMALLINT','MEDIUMINT','INT','BIGINT','FLOAT','DOUBLE','DECIMAL','DATE','DATETIME','TIMESTAMP','TIME','YEAR'), + length BIGINT UNSIGNED NULL, + ordinal_position INTEGER NOT NULL, + index_length BIGINT UNSIGNED NULL, description VARCHAR(2048), - size BIGINT, - d BIGINT, - auto_generated BOOLEAN DEFAULT false, - is_null_allowed BOOLEAN NOT NULL DEFAULT true, - val_min NUMERIC NULL, - val_max NUMERIC NULL, - mean NUMERIC NULL, - median NUMERIC NULL, - std_dev Numeric NULL, - created timestamp NOT NULL DEFAULT NOW(), + size BIGINT UNSIGNED, + d BIGINT UNSIGNED, + is_null_allowed BOOLEAN NOT NULL DEFAULT true, + val_min NUMERIC NULL, + val_max NUMERIC NULL, + mean NUMERIC NULL, + median NUMERIC NULL, + std_dev Numeric NULL, + created timestamp NOT NULL DEFAULT NOW(), last_modified timestamp, FOREIGN KEY (tID) REFERENCES mdb_tables (ID) ON DELETE CASCADE, - PRIMARY KEY (ID) + PRIMARY KEY (ID), + UNIQUE (tID, internal_name) ) WITH SYSTEM VERSIONING; CREATE TABLE IF NOT EXISTS `mdb_columns_enums` ( - id bigint NOT NULL AUTO_INCREMENT, - column_id bigint NOT NULL, + id SERIAL, + column_id BIGINT UNSIGNED NOT NULL, value CHARACTER VARYING(255) NOT NULL, FOREIGN KEY (column_id) REFERENCES mdb_columns (ID) ON DELETE CASCADE, PRIMARY KEY (id) @@ -188,8 +175,8 @@ CREATE TABLE IF NOT EXISTS `mdb_columns_enums` CREATE TABLE IF NOT EXISTS `mdb_columns_sets` ( - id bigint NOT NULL AUTO_INCREMENT, - column_id bigint NOT NULL, + id SERIAL, + column_id BIGINT UNSIGNED NOT NULL, value CHARACTER VARYING(255) NOT NULL, FOREIGN KEY (column_id) REFERENCES mdb_columns (ID) ON DELETE CASCADE, PRIMARY KEY (id) @@ -197,36 +184,36 @@ CREATE TABLE IF NOT EXISTS `mdb_columns_sets` CREATE TABLE IF NOT EXISTS `mdb_columns_nom` ( - tID bigint, - cID bigint, + cID BIGINT UNSIGNED, + tID BIGINT UNSIGNED, maxlength INTEGER, last_modified timestamp, created timestamp NOT NULL DEFAULT NOW(), - FOREIGN KEY (tID, cID) REFERENCES mdb_columns (tID, ID), - PRIMARY KEY (tID, cID) + PRIMARY KEY (cID), + FOREIGN KEY (cID) REFERENCES mdb_columns (ID) ) WITH SYSTEM VERSIONING; CREATE TABLE IF NOT EXISTS `mdb_columns_cat` ( - tID bigint, - cID bigint, + cID BIGINT UNSIGNED, + tID BIGINT UNSIGNED, num_cat INTEGER, -- cat_array TEXT[], last_modified timestamp, created timestamp NOT NULL DEFAULT NOW(), - FOREIGN KEY (tID, cID) REFERENCES mdb_columns (tID, ID), - PRIMARY KEY (tID, cID) + PRIMARY KEY (cID), + FOREIGN KEY (cID) REFERENCES mdb_columns (ID) ) WITH SYSTEM VERSIONING; CREATE TABLE IF NOT EXISTS `mdb_constraints_foreign_key` ( - fkid BIGINT NOT NULL AUTO_INCREMENT, - tid BIGINT NOT NULL, - rtid BIGINT NOT NULL, - name VARCHAR(255) NOT NULL, - on_update VARCHAR(50) NULL, - on_delete VARCHAR(50) NULL, - position INT NULL, + fkid SERIAL, + tid BIGINT UNSIGNED NOT NULL, + rtid BIGINT UNSIGNED NOT NULL, + name VARCHAR(255) NOT NULL, + on_update VARCHAR(50) NULL, + on_delete VARCHAR(50) NULL, + position INT NULL, PRIMARY KEY (fkid), FOREIGN KEY (tid) REFERENCES mdb_tables (id) ON DELETE CASCADE, FOREIGN KEY (rtid) REFERENCES mdb_tables (id) @@ -234,9 +221,9 @@ CREATE TABLE IF NOT EXISTS `mdb_constraints_foreign_key` CREATE TABLE IF NOT EXISTS `mdb_constraints_primary_key` ( - pkid BIGINT NOT NULL AUTO_INCREMENT, - tID BIGINT NOT NULL, - cid BIGINT NOT NULL, + pkid SERIAL, + tID BIGINT UNSIGNED NOT NULL, + cid BIGINT UNSIGNED NOT NULL, PRIMARY KEY (pkid), FOREIGN KEY (tID) REFERENCES mdb_tables (id) ON DELETE CASCADE, FOREIGN KEY (cid) REFERENCES mdb_columns (id) ON DELETE CASCADE @@ -244,10 +231,10 @@ CREATE TABLE IF NOT EXISTS `mdb_constraints_primary_key` CREATE TABLE IF NOT EXISTS `mdb_constraints_foreign_key_reference` ( - id BIGINT NOT NULL AUTO_INCREMENT, - fkid BIGINT NOT NULL, - cid BIGINT NOT NULL, - rcid BIGINT NOT NULL, + id SERIAL, + fkid BIGINT UNSIGNED NOT NULL, + cid BIGINT UNSIGNED NOT NULL, + rcid BIGINT UNSIGNED NOT NULL, PRIMARY KEY (id), UNIQUE (fkid, cid, rcid), FOREIGN KEY (fkid) REFERENCES mdb_constraints_foreign_key (fkid) ON UPDATE CASCADE, @@ -257,19 +244,19 @@ CREATE TABLE IF NOT EXISTS `mdb_constraints_foreign_key_reference` CREATE TABLE IF NOT EXISTS `mdb_constraints_unique` ( - uid BIGINT NOT NULL AUTO_INCREMENT, - name VARCHAR(255) NOT NULL, - tid BIGINT NOT NULL, - position INT NULL, + uid SERIAL, + name VARCHAR(255) NOT NULL, + tid BIGINT UNSIGNED NOT NULL, + position INT NULL, PRIMARY KEY (uid), FOREIGN KEY (tid) REFERENCES mdb_tables (id) ON DELETE CASCADE ); CREATE TABLE IF NOT EXISTS `mdb_constraints_unique_columns` ( - id BIGINT NOT NULL AUTO_INCREMENT, - uid BIGINT NOT NULL, - cid BIGINT NOT NULL, + id SERIAL, + uid BIGINT UNSIGNED NOT NULL, + cid BIGINT UNSIGNED NOT NULL, PRIMARY KEY (id), FOREIGN KEY (uid) REFERENCES mdb_constraints_unique (uid), FOREIGN KEY (cid) REFERENCES mdb_columns (id) ON DELETE CASCADE @@ -277,9 +264,9 @@ CREATE TABLE IF NOT EXISTS `mdb_constraints_unique_columns` CREATE TABLE IF NOT EXISTS `mdb_constraints_checks` ( - id BIGINT NOT NULL AUTO_INCREMENT, - tid BIGINT NOT NULL, - checks VARCHAR(255) NOT NULL, + id SERIAL, + tid BIGINT UNSIGNED NOT NULL, + checks VARCHAR(255) NOT NULL, PRIMARY KEY (id), FOREIGN KEY (tid) REFERENCES mdb_tables (id) ON DELETE CASCADE ) WITH SYSTEM VERSIONING; @@ -287,7 +274,7 @@ CREATE TABLE IF NOT EXISTS `mdb_constraints_checks` CREATE TABLE IF NOT EXISTS `mdb_concepts` ( - id bigint NOT NULL AUTO_INCREMENT, + id SERIAL, uri text not null, name VARCHAR(255) null, description TEXT null, @@ -298,7 +285,7 @@ CREATE TABLE IF NOT EXISTS `mdb_concepts` CREATE TABLE IF NOT EXISTS `mdb_units` ( - id bigint NOT NULL AUTO_INCREMENT, + id SERIAL, uri text not null, name VARCHAR(255) null, description TEXT null, @@ -309,26 +296,26 @@ CREATE TABLE IF NOT EXISTS `mdb_units` CREATE TABLE IF NOT EXISTS `mdb_columns_concepts` ( - id bigint NOT NULL, - cID bigint NOT NULL, - created timestamp NOT NULL DEFAULT NOW(), + id BIGINT UNSIGNED NOT NULL, + cID BIGINT UNSIGNED NOT NULL, + created timestamp NOT NULL DEFAULT NOW(), PRIMARY KEY (id, cid), FOREIGN KEY (cID) REFERENCES mdb_columns (ID) ) WITH SYSTEM VERSIONING; CREATE TABLE IF NOT EXISTS `mdb_columns_units` ( - id bigint NOT NULL, - cID bigint NOT NULL, - created timestamp NOT NULL DEFAULT NOW(), + id BIGINT UNSIGNED NOT NULL, + cID BIGINT UNSIGNED NOT NULL, + created timestamp NOT NULL DEFAULT NOW(), PRIMARY KEY (id, cID), FOREIGN KEY (cID) REFERENCES mdb_columns (ID) ) WITH SYSTEM VERSIONING; CREATE TABLE IF NOT EXISTS `mdb_view` ( - id bigint NOT NULL AUTO_INCREMENT, - vdbid bigint NOT NULL, + id SERIAL, + vdbid BIGINT UNSIGNED NOT NULL, vName VARCHAR(64) NOT NULL, internal_name VARCHAR(64) NOT NULL, Query TEXT NOT NULL, @@ -345,7 +332,7 @@ CREATE TABLE IF NOT EXISTS `mdb_view` CREATE TABLE IF NOT EXISTS `mdb_banner_messages` ( - id bigint NOT NULL AUTO_INCREMENT, + id SERIAL, type ENUM ('ERROR', 'WARNING', 'INFO') NOT NULL default 'INFO', message TEXT NOT NULL, link TEXT NULL, @@ -357,7 +344,7 @@ CREATE TABLE IF NOT EXISTS `mdb_banner_messages` CREATE TABLE IF NOT EXISTS `mdb_ontologies` ( - id bigint NOT NULL AUTO_INCREMENT, + id SERIAL, prefix VARCHAR(8) NOT NULL, uri TEXT NOT NULL, uri_pattern TEXT, @@ -372,28 +359,27 @@ CREATE TABLE IF NOT EXISTS `mdb_ontologies` CREATE TABLE IF NOT EXISTS `mdb_view_columns` ( - id BIGINT NOT NULL AUTO_INCREMENT, - view_id BIGINT NOT NULL, - dfID BIGINT, + id SERIAL, + view_id BIGINT UNSIGNED NOT NULL, name VARCHAR(64), - internal_name VARCHAR(64) NOT NULL, + internal_name VARCHAR(64) NOT NULL, column_type ENUM ('CHAR','VARCHAR','BINARY','VARBINARY','TINYBLOB','TINYTEXT','TEXT','BLOB','MEDIUMTEXT','MEDIUMBLOB','LONGTEXT','LONGBLOB','ENUM','SET','BIT','TINYINT','BOOL','SMALLINT','MEDIUMINT','INT','BIGINT','FLOAT','DOUBLE','DECIMAL','DATE','DATETIME','TIMESTAMP','TIME','YEAR'), - ordinal_position INTEGER NOT NULL, - size BIGINT, - d BIGINT, - auto_generated BOOLEAN DEFAULT false, - is_null_allowed BOOLEAN NOT NULL DEFAULT true, + ordinal_position INTEGER NOT NULL, + size BIGINT UNSIGNED, + d BIGINT UNSIGNED, + is_null_allowed BOOLEAN NOT NULL DEFAULT true, PRIMARY KEY (id), - FOREIGN KEY (view_id) REFERENCES mdb_view (id) + FOREIGN KEY (view_id) REFERENCES mdb_view (id) ON DELETE CASCADE, + UNIQUE (view_id, internal_name) ) WITH SYSTEM VERSIONING; CREATE TABLE IF NOT EXISTS `mdb_identifiers` ( - id BIGINT NOT NULL AUTO_INCREMENT, - dbid BIGINT NOT NULL, - qid BIGINT, - vid BIGINT, - tid BIGINT, + id SERIAL, + dbid BIGINT UNSIGNED NOT NULL, + qid BIGINT UNSIGNED, + vid BIGINT UNSIGNED, + tid BIGINT UNSIGNED, publisher VARCHAR(255) NOT NULL, language VARCHAR(2), publication_year INTEGER NOT NULL, @@ -418,8 +404,8 @@ CREATE TABLE IF NOT EXISTS `mdb_identifiers` CREATE TABLE IF NOT EXISTS `mdb_identifier_licenses` ( - pid bigint NOT NULL, - license_id VARCHAR(255) NOT NULL, + pid BIGINT UNSIGNED NOT NULL, + license_id VARCHAR(255) NOT NULL, PRIMARY KEY (pid, license_id), FOREIGN KEY (pid) REFERENCES mdb_identifiers (id), FOREIGN KEY (license_id) REFERENCES mdb_licenses (identifier) @@ -427,9 +413,9 @@ CREATE TABLE IF NOT EXISTS `mdb_identifier_licenses` CREATE TABLE IF NOT EXISTS `mdb_identifier_titles` ( - id bigint NOT NULL AUTO_INCREMENT, - pid bigint NOT NULL, - title text NOT NULL, + id SERIAL, + pid BIGINT UNSIGNED NOT NULL, + title text NOT NULL, title_type ENUM ('ALTERNATIVE_TITLE', 'SUBTITLE', 'TRANSLATED_TITLE', 'OTHER'), language VARCHAR(2), PRIMARY KEY (id), @@ -438,9 +424,9 @@ CREATE TABLE IF NOT EXISTS `mdb_identifier_titles` CREATE TABLE IF NOT EXISTS `mdb_identifier_funders` ( - id bigint NOT NULL AUTO_INCREMENT, - pid bigint NOT NULL, - funder_name VARCHAR(255) NOT NULL, + id SERIAL, + pid BIGINT UNSIGNED NOT NULL, + funder_name VARCHAR(255) NOT NULL, funder_identifier TEXT, funder_identifier_type ENUM ('CROSSREF_FUNDER_ID', 'GRID', 'ISNI', 'ROR', 'OTHER'), scheme_uri text, @@ -453,9 +439,9 @@ CREATE TABLE IF NOT EXISTS `mdb_identifier_funders` CREATE TABLE IF NOT EXISTS `mdb_identifier_descriptions` ( - id bigint NOT NULL AUTO_INCREMENT, - pid bigint NOT NULL, - description text NOT NULL, + id SERIAL, + pid BIGINT UNSIGNED NOT NULL, + description text NOT NULL, description_type ENUM ('ABSTRACT', 'METHODS', 'SERIES_INFORMATION', 'TABLE_OF_CONTENTS', 'TECHNICAL_INFO', 'OTHER'), language VARCHAR(2), PRIMARY KEY (id), @@ -464,11 +450,11 @@ CREATE TABLE IF NOT EXISTS `mdb_identifier_descriptions` CREATE TABLE IF NOT EXISTS `mdb_related_identifiers` ( - id bigint NOT NULL AUTO_INCREMENT, - pid bigint NOT NULL, - value varchar(255) NOT NULL, - type varchar(255) NOT NULL, - relation varchar(255) NOT NULL, + id SERIAL, + pid BIGINT UNSIGNED NOT NULL, + value varchar(255) NOT NULL, + type varchar(255) NOT NULL, + relation varchar(255) NOT NULL, PRIMARY KEY (id), /* must be a single id from persistent identifier concept */ FOREIGN KEY (pid) REFERENCES mdb_identifiers (id), UNIQUE (pid, value) @@ -476,11 +462,11 @@ CREATE TABLE IF NOT EXISTS `mdb_related_identifiers` CREATE TABLE IF NOT EXISTS `mdb_identifier_creators` ( - id bigint NOT NULL AUTO_INCREMENT, - pid bigint NOT NULL, + id SERIAL, + pid BIGINT UNSIGNED NOT NULL, given_names text, family_name text, - creator_name VARCHAR(255) NOT NULL, + creator_name VARCHAR(255) NOT NULL, name_type ENUM ('PERSONAL', 'ORGANIZATIONAL') default 'PERSONAL', name_identifier text, name_identifier_scheme ENUM ('ROR', 'GRID', 'ISNI', 'ORCID'), @@ -496,7 +482,7 @@ CREATE TABLE IF NOT EXISTS `mdb_identifier_creators` CREATE TABLE IF NOT EXISTS `mdb_update` ( uUserID character varying(255) NOT NULL, - uDBID bigint NOT NULL, + uDBID BIGINT UNSIGNED NOT NULL, created timestamp NOT NULL DEFAULT NOW(), PRIMARY KEY (uUserID, uDBID), FOREIGN KEY (uDBID) REFERENCES mdb_databases (id) @@ -505,7 +491,7 @@ CREATE TABLE IF NOT EXISTS `mdb_update` CREATE TABLE IF NOT EXISTS `mdb_access` ( aUserID character varying(255) NOT NULL, - aDBID bigint REFERENCES mdb_databases (id), + aDBID BIGINT UNSIGNED REFERENCES mdb_databases (id), attime TIMESTAMP, download BOOLEAN, created timestamp NOT NULL DEFAULT NOW(), @@ -515,14 +501,42 @@ CREATE TABLE IF NOT EXISTS `mdb_access` CREATE TABLE IF NOT EXISTS `mdb_have_access` ( user_id character varying(36) NOT NULL, - database_id bigint REFERENCES mdb_databases (id), + database_id BIGINT UNSIGNED REFERENCES mdb_databases (id), access_type ENUM ('READ', 'WRITE_OWN', 'WRITE_ALL') NOT NULL, created timestamp NOT NULL DEFAULT NOW(), PRIMARY KEY (user_id, database_id), FOREIGN KEY (user_id) REFERENCES mdb_users (id) ) WITH SYSTEM VERSIONING; +CREATE TABLE IF NOT EXISTS `mdb_image_types` +( + id SERIAL, + image_id BIGINT UNSIGNED NOT NULL, + display_name varchar(255) NOT NULL, + value varchar(255) NOT NULL, + size_min INT UNSIGNED, + size_max INT UNSIGNED, + size_default INT UNSIGNED, + size_required BOOLEAN COMMENT 'When setting NULL, the service assumes the data type has no size', + size_step INT UNSIGNED, + d_min INT UNSIGNED, + d_max INT UNSIGNED, + d_default INT UNSIGNED, + d_required BOOLEAN COMMENT 'When setting NULL, the service assumes the data type has no d', + d_step INT UNSIGNED, + type_hint TEXT, + data_hint TEXT, + documentation TEXT NOT NULL, + is_generated BOOLEAN NOT NULL, + is_quoted BOOLEAN NOT NULL, + is_buildable BOOLEAN NOT NULL, + PRIMARY KEY (id), + FOREIGN KEY (image_id) REFERENCES `mdb_images` (`id`), + UNIQUE (value) +) WITH SYSTEM VERSIONING; + COMMIT; + BEGIN; INSERT INTO `mdb_licenses` (identifier, uri, description) @@ -535,15 +549,79 @@ INSERT INTO `mdb_images` (name, registry, version, default_port, dialect, driver VALUES ('mariadb', 'docker.io', '11.1.3', 3306, 'org.hibernate.dialect.MariaDBDialect', 'org.mariadb.jdbc.Driver', 'mariadb'); -INSERT INTO `mdb_images_date` (iid, database_format, unix_format, example, has_time) -VALUES (1, '%Y-%c-%d %H:%i:%S.%f', 'yyyy-MM-dd HH:mm:ss.SSSSSS', '2022-01-30 13:44:25.499', true), - (1, '%Y-%c-%d %H:%i:%S', 'yyyy-MM-dd HH:mm:ss', '2022-01-30 13:44:25', true), - (1, '%Y-%c-%d', 'yyyy-MM-dd', '2022-01-30', false), - (1, '%H:%i:%S', 'HH:mm:ss', '13:44:25', true), - (1, '%d.%c.%Y', 'dd.MM.yyyy', '30.01.2022', false); - -INSERT INTO `mdb_ontologies` (prefix, uri, uri_pattern, sparql_endpoint, rdf_path) -VALUES ('om2', 'http://www.ontology-of-units-of-measure.org/resource/om-2/', +INSERT INTO `mdb_image_types` (image_id, display_name, value, size_min, size_max, size_default, size_required, + size_step, d_min, d_max, d_default, d_required, d_step, type_hint, data_hint, + documentation, is_quoted, is_buildable, is_generated) +VALUES (1, 'BIGINT(size)', 'bigint', 0, null, null, false, 1, null, null, null, null, null, null, null, + 'https://mariadb.com/kb/en/bigint/', false, true, false), + (1, 'BINARY(size)', 'binary', 0, 255, 255, true, 1, null, null, null, null, null, 'size in Bytes', null, + 'https://mariadb.com/kb/en/binary/', false, true, false), + (1, 'BIT(size)', 'bit', 0, 64, null, false, 1, null, null, null, null, null, null, null, + 'https://mariadb.com/kb/en/bit/', false, true, false), + (1, 'BLOB(size)', 'blob', 0, 65535, null, false, 1, null, null, null, null, null, 'size in Bytes', null, + 'https://mariadb.com/kb/en/blob/', false, false, false), + (1, 'BOOL', 'bool', null, null, null, null, null, null, null, null, null, null, null, null, + 'https://mariadb.com/kb/en/bool/', false, true, false), + (1, 'CHAR(size)', 'char', 0, 255, 255, false, 1, null, null, null, null, null, null, null, + 'https://mariadb.com/kb/en/char/', false, true, false), + (1, 'DATE', 'date', null, null, null, null, null, null, null, null, null, null, + 'min. 1000-01-01, max. 9999-12-31', 'e.g. YYYY-MM-DD, YY-MM-DD, YYMMDD, YYYY/MM/DD', + 'https://mariadb.com/kb/en/date/', true, true, false), + (1, 'DATETIME(fsp)', 'datetime', 0, 6, null, null, 1, null, null, null, null, null, + 'fsp=microsecond precision, min. 1000-01-01 00:00:00.0, max. 9999-12-31 23:59:59.9', + 'e.g. YYYY-MM-DD HH:MM:SS, YY-MM-DD HH:MM:SS, YYYYMMDDHHMMSS, YYMMDDHHMMSS, YYYYMMDD, YYMMDD', + 'https://mariadb.com/kb/en/datetime/', true, true, false), + (1, 'DECIMAL(size, d)', 'decimal', 0, 65, null, false, 1, 0, 38, null, false, null, null, null, + 'https://mariadb.com/kb/en/decimal/', false, true, false), + (1, 'DOUBLE(size, d)', 'double', null, null, null, false, null, null, null, null, false, null, null, null, + 'https://mariadb.com/kb/en/double/', false, true, false), + (1, 'ENUM(v1,v2,...)', 'enum', null, null, null, null, null, null, null, null, null, null, null, + 'e.g. value1, value2, ...', 'https://mariadb.com/kb/en/enum/', true, true, false), + (1, 'FLOAT(size)', 'float', null, null, null, false, null, null, null, null, null, null, null, null, + 'https://mariadb.com/kb/en/float/', false, true, false), + (1, 'INT(size)', 'int', null, null, null, false, null, null, null, null, null, null, 'size in Bytes', null, + 'https://mariadb.com/kb/en/int/', false, true, false), + (1, 'LONGBLOB', 'longblob', null, null, null, null, null, null, null, null, null, null, 'max. 3.999 GiB', null, + 'https://mariadb.com/kb/en/longblob/', false, true, false), + (1, 'LONGTEXT', 'longtext', null, null, null, null, null, null, null, null, null, null, 'max. 3.999 GiB', null, + 'https://mariadb.com/kb/en/longtext/', true, true, false), + (1, 'MEDIUMBLOB', 'mediumblob', null, null, null, null, null, null, null, null, null, null, 'max. 15.999 MiB', + null, 'https://mariadb.com/kb/en/mediumblob/', false, true, false), + (1, 'MEDIUMINT', 'mediumint', null, null, null, null, null, null, null, null, null, null, 'size in Bytes', null, + 'https://mariadb.com/kb/en/mediumint/', false, true, false), + (1, 'MEDIUMTEXT', 'mediumtext', null, null, null, null, null, null, null, null, null, null, 'size in Bytes', + null, 'https://mariadb.com/kb/en/mediumtext/', true, true, false), + (1, 'SERIAL', 'serial', null, null, null, null, null, null, null, null, null, null, null, + null, 'https://mariadb.com/kb/en/bigint/', true, true, true), + (1, 'SET(v1,v2,...)', 'set', null, null, null, null, null, null, null, null, null, null, null, + 'e.g. value1, value2, ...', 'https://mariadb.com/kb/en/set/', true, true, false), + (1, 'SMALLINT(size)', 'smallint', 0, null, null, false, null, null, null, null, null, null, 'size in Bytes', + null, 'https://mariadb.com/kb/en/smallint/', false, true, false), + (1, 'TEXT(size)', 'text', 0, null, null, false, null, null, null, null, null, null, 'size in Bytes', null, + 'https://mariadb.com/kb/en/text/', true, true, false), + (1, 'TIME(fsp)', 'time', 0, 6, 0, false, null, null, null, null, null, null, + 'fsp=microsecond precision, min. 0, max. 6', 'e.g. HH:MM:SS, HH:MM, HHMMSS, H:M:S', + 'https://mariadb.com/kb/en/time/', true, true, false), + (1, 'TIMESTAMP(fsp)', 'timestamp', 0, 6, 0, false, null, null, null, null, null, null, + 'fsp=microsecond precision, min. 0, max. 6', + 'e.g. YYYY-MM-DD HH:MM:SS, YY-MM-DD HH:MM:SS, YYYYMMDDHHMMSS, YYMMDDHHMMSS, YYYYMMDD, YYMMDD', + 'https://mariadb.com/kb/en/timestamp/', true, true, false), + (1, 'TINYBLOB', 'tinyblob', null, null, null, null, null, null, null, null, null, null, null, + 'fsp=microsecond precision, min. 0, max. 6', 'https://mariadb.com/kb/en/timestamp/', false, true, false), + (1, 'TINYINT(size)', 'tinyint', 0, null, null, false, null, null, null, null, null, null, null, + 'size in Bytes', 'https://mariadb.com/kb/en/tinyint/', false, true, false), + (1, 'TINYTEXT', 'tinytext', null, null, null, null, null, null, null, null, null, null, null, + 'max. 255 characters', 'https://mariadb.com/kb/en/tinytext/', true, true, false), + (1, 'YEAR', 'year', 2, 4, null, false, 2, null, null, null, null, null, 'min. 1901, max. 2155', 'e.g. YYYY, YY', + 'https://mariadb.com/kb/en/year/', false, true, false), + (1, 'VARBINARY(size)', 'varbinary', 0, null, null, true, null, null, null, null, null, null, null, + null, 'https://mariadb.com/kb/en/varbinary/', false, true, false), + (1, 'VARCHAR(size)', 'varchar', 0, 65532, 255, true, null, null, null, null, null, null, null, + null, 'https://mariadb.com/kb/en/varchar/', false, true, false); + +INSERT +INTO `mdb_ontologies` (prefix, uri, uri_pattern, sparql_endpoint, rdf_path) +VALUES ('om', 'http://www.ontology-of-units-of-measure.org/resource/om-2/', 'http://www.ontology-of-units-of-measure.org/resource/om-2/.*', null, 'rdf/om-2.0.rdf'), ('wd', 'http://www.wikidata.org/', 'http://www.wikidata.org/entity/.*', 'https://query.wikidata.org/sparql', null), @@ -566,4 +644,4 @@ VALUES ('om2', 'http://www.ontology-of-units-of-measure.org/resource/om-2/', ('weather', 'https://www.auto.tuwien.ac.at/downloads/thinkhome/ontology/WeatherOntology.owl', 'https://www.auto.tuwien.ac.at/downloads/thinkhome/ontology/WeatherOntology.owl/*', null, null), ('qudt', 'http://qudt.org/2.1/vocab/quantitykind', 'http://qudt.org/2.1/vocab/quantitykind/*', null, null), ('ucum', 'http://elite.polito.it/ontologies/ucum-instances.owl', 'http://elite.polito.it/ontologies/ucum-instances.owl/*', null, null); -COMMIT; +COMMIT; \ No newline at end of file diff --git a/dbrepo-metadata-db/2_setup-data.sql b/dbrepo-metadata-db/2_setup-data.sql index 24e587fc50cb9beb6363c6bc562c7120a9d9a714..e806e1e181dbdcc3f0e4e29f837bffac7123317c 100644 --- a/dbrepo-metadata-db/2_setup-data.sql +++ b/dbrepo-metadata-db/2_setup-data.sql @@ -2,7 +2,7 @@ BEGIN; INSERT INTO `mdb_containers` (name, internal_name, image_id, host, port, ui_host, ui_port, sidecar_host, sidecar_port, privileged_username, privileged_password) -VALUES ('MariaDB 11.1.3', 'mariadb_11_1_3', 1, 'data-db', 3306, 'localhost', 3306, 'data-db-sidecar', 8080, +VALUES ('mariadb:11.1.3-debian-11-r6', 'mariadb_11_1_3', 1, 'data-db', 3306, 'localhost', 3306, 'data-db-sidecar', 8080, 'root', 'dbrepo'); COMMIT; diff --git a/dbrepo-metadata-service/api/pom.xml b/dbrepo-metadata-service/api/pom.xml index b62bfdc94ad922ffa7b1c8f44e3f1e54d89a2d87..c5dadcdfd9ff4aebd0ce83c59b55a2d2d45c237b 100644 --- a/dbrepo-metadata-service/api/pom.xml +++ b/dbrepo-metadata-service/api/pom.xml @@ -6,14 +6,21 @@ <parent> <groupId>at.tuwien</groupId> <artifactId>dbrepo-metadata-service</artifactId> - <version>1.4.5</version> + <version>1.4.7</version> </parent> <artifactId>dbrepo-metadata-service-api</artifactId> <name>dbrepo-metadata-service-api</name> - <version>1.4.5</version> + <version>1.4.7</version> - <dependencies/> + <dependencies> + <dependency> + <groupId>at.tuwien</groupId> + <artifactId>dbrepo-metadata-service-entities</artifactId> + <version>1.4.7</version> + <scope>compile</scope> + </dependency> + </dependencies> <build> <plugins> diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/ContainerBriefDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/ContainerBriefDto.java index aa3b1ad91ff5fb8608885a2a41a3f2656969dd66..7acd4fc3ce7d225eb38de8a369dc34c60d185c49 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/ContainerBriefDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/ContainerBriefDto.java @@ -40,8 +40,12 @@ public class ContainerBriefDto { private ImageBriefDto image; @NotNull - @Schema(example = "true") - private Boolean running; + @Schema(example = "50") + private Integer quota; + + @NotNull + @Schema(example = "10") + private Integer count; @NotNull @Schema(example = "2021-03-12T15:26:21Z") diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/ContainerCreateDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/ContainerCreateDto.java index d5b8f827c2e95a531961f6e48a862e8457229795..7080d2b5d96e2763a8ebf750eea27f9b08fa4a50 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/ContainerCreateDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/ContainerCreateDto.java @@ -46,6 +46,10 @@ public class ContainerCreateDto { @JsonProperty("ui_port") private Integer uiPort; + @NotNull + @Schema(example = "50") + private Long quota; + @NotBlank @JsonProperty("privileged_username") @Schema(description = "Username of privileged user", example = "root") diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/ContainerDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/ContainerDto.java index d7c6727be71331d51e967d04d008f7b7ba70ad99..7e46b80c1cfc745b158f6bffffd02bdd617a1987 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/ContainerDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/ContainerDto.java @@ -54,6 +54,14 @@ public class ContainerDto { @NotNull private ImageDto image; + @NotNull + @Schema(example = "50") + private Long quota; + + @NotNull + @Schema(example = "10") + private Long count; + @NotNull @Schema(example = "2021-03-12T15:26:21Z") @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX", timezone = "UTC") diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/image/DataTypeDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/image/DataTypeDto.java new file mode 100644 index 0000000000000000000000000000000000000000..312dcf998417f13c6d552dcb25d843516f799f1e --- /dev/null +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/image/DataTypeDto.java @@ -0,0 +1,78 @@ +package at.tuwien.api.container.image; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.*; +import lombok.extern.jackson.Jacksonized; + +@Getter +@Setter +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Jacksonized +@ToString +public class DataTypeDto { + + @NotBlank + @JsonProperty("display_name") + @Schema(example = "TIME(fsp)") + private String displayName; + + @NotBlank + @Schema(example = "time") + private String value; + + @JsonProperty("size_min") + @Schema(example = "0") + private Integer sizeMin; + + @JsonProperty("size_max") + @Schema(example = "6") + private Integer sizeMax; + + @JsonProperty("size_default") + @Schema(example = "0") + private Integer sizeDefault; + + @JsonProperty("size_required") + @Schema(example = "false") + private Boolean sizeRequired; + + @JsonProperty("d_min") + private Integer dMin; + + @JsonProperty("d_max") + private Integer dMax; + + @JsonProperty("d_default") + private Integer dDefault; + + @JsonProperty("d_required") + private Boolean dRequired; + + @NotNull + @Schema(example = "https://mariadb.com/kb/en/time/") + private String documentation; + + @JsonProperty("data_hint") + @Schema(example = "e.g. HH:MM:SS, HH:MM, HHMMSS, H:M:S") + private String dataHint; + + @JsonProperty("type_hint") + @Schema(example = "fsp=microsecond precision, min. 0, max. 6") + private String typeHint; + + @NotNull + @JsonProperty("is_quoted") + @Schema(example = "false", description = "frontend needs to quote this data type") + private Boolean quoted; + + @NotNull + @JsonProperty("is_buildable") + @Schema(example = "true", description = "frontend can build this data type") + private Boolean buildable; + +} diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/image/ImageBriefDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/image/ImageBriefDto.java index e336f3d47a9444aace3e2c66acffe825c1bae128..38adbd6f0d6592a0e802d2bf33147916bbd9f139 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/image/ImageBriefDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/image/ImageBriefDto.java @@ -32,4 +32,9 @@ public class ImageBriefDto { @Schema(example = "mariadb") private String jdbcMethod; + @NotNull + @JsonProperty("default") + @Schema(example = "false") + private Boolean isDefault; + } diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/image/ImageCreateDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/image/ImageCreateDto.java index 2031ee15aa6ed44d60682315604a726fe7af03c6..4e9fea5b7cbada74155ad2760ccdc99fb2e23490 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/image/ImageCreateDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/image/ImageCreateDto.java @@ -27,6 +27,11 @@ public class ImageCreateDto { @Schema(example = "mariadb") private String name; + @NotNull + @JsonProperty("is_default") + @Schema(example = "false") + private Boolean isDefault; + @NotBlank @Parameter(example = "10.5") private String version; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/image/ImageDateDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/image/ImageDateDto.java deleted file mode 100644 index 6fc25ad3cb3ddf860d11e9b4a5ac4ae75b98c277..0000000000000000000000000000000000000000 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/image/ImageDateDto.java +++ /dev/null @@ -1,48 +0,0 @@ -package at.tuwien.api.container.image; - -import com.fasterxml.jackson.annotation.JsonFormat; -import com.fasterxml.jackson.annotation.JsonProperty; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.*; - -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotNull; -import lombok.extern.jackson.Jacksonized; - -import java.time.Instant; - -@Getter -@Setter -@Builder -@NoArgsConstructor -@AllArgsConstructor -@Jacksonized -@ToString -public class ImageDateDto { - - @NotNull - private Long id; - - @NotBlank - @JsonProperty("database_format") - @Schema(example = "%d.%c.%Y") - private String databaseFormat; - - @NotBlank - @JsonProperty("unix_format") - @Schema(example = "dd.MM.YYYY") - private String unixFormat; - - @NotNull - @JsonProperty("has_time") - @Schema(example = "false") - private Boolean hasTime; - - - @NotNull - @Schema(example = "2021-03-12T15:26:21Z") - @JsonProperty("created_at") - @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX", timezone = "UTC") - private Instant createdAt; - -} diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/image/ImageDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/image/ImageDto.java index 3d766e3abae3379636e6c541d094a89f354dfce3..743f1f2b0a8ab67795a58b060d6ef30597d36837 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/image/ImageDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/image/ImageDto.java @@ -38,9 +38,6 @@ public class ImageDto { @Schema(example = "org.mariadb.jdbc.Driver") private String driverClass; - @JsonProperty("date_formats") - private List<ImageDateDto> dateFormats; - @NotBlank @Schema(example = "org.hibernate.dialect.MariaDBDialect") private String dialect; @@ -50,9 +47,18 @@ public class ImageDto { @Schema(example = "mariadb") private String jdbcMethod; + @NotNull + @JsonProperty("default") + @Schema(example = "false") + private Boolean isDefault; + @NotNull @JsonProperty("default_port") @Schema(example = "3306") private Integer defaultPort; + @NotNull + @JsonProperty("data_types") + private List<DataTypeDto> dataTypes; + } diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/internal/PrivilegedContainerDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/internal/PrivilegedContainerDto.java index 8de17a48f3221ed4ace1d837ec67183186731381..8bda16bf41630376ad105399ca1aca048d1514e6 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/internal/PrivilegedContainerDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/internal/PrivilegedContainerDto.java @@ -1,6 +1,5 @@ package at.tuwien.api.container.internal; -import at.tuwien.api.container.image.ImageDateDto; import at.tuwien.api.container.image.ImageDto; import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/ViewColumnDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/ViewColumnDto.java index 337a61a637ea03437f74462c3b1c245e6943999d..613f9c5e71e54bdc09a8c78752d7a40f0eb0eb88 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/ViewColumnDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/ViewColumnDto.java @@ -1,6 +1,5 @@ package at.tuwien.api.database; -import at.tuwien.api.container.image.ImageDateDto; import at.tuwien.api.database.table.columns.ColumnTypeDto; import at.tuwien.api.database.table.columns.concepts.ConceptDto; import at.tuwien.api.database.table.columns.concepts.UnitDto; @@ -44,12 +43,6 @@ public class ViewColumnDto { @Schema(example = "mdb_date") private String internalName; - @Schema - private String alias; - - @JsonProperty("date_format") - private ImageDateDto dateFormat; - @NotNull @JsonProperty("auto_generated") @Schema(example = "false") diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/ImportCsvDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/ImportCsvDto.java deleted file mode 100644 index eac536143e1b59efce8617f740334acc74b77f5a..0000000000000000000000000000000000000000 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/ImportCsvDto.java +++ /dev/null @@ -1,49 +0,0 @@ -package at.tuwien.api.database.query; - -import com.fasterxml.jackson.annotation.JsonProperty; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.*; - -import jakarta.validation.constraints.Min; -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotNull; -import lombok.extern.jackson.Jacksonized; - -@Getter -@Setter -@Builder -@NoArgsConstructor -@AllArgsConstructor -@Jacksonized -@ToString -public class ImportCsvDto { - - @NotBlank - @Schema(example = "file.csv") - private String location; - - @Min(value = 0L) - @JsonProperty("skip_lines") - private Long skipLines; - - @JsonProperty("false_element") - private String falseElement; - - @JsonProperty("true_element") - private String trueElement; - - @JsonProperty("null_element") - @Schema(example = "NA") - private String nullElement; - - @NotNull - @Schema(example = ",") - private Character separator; - - @Schema(example = "\"") - private Character quote; - - @JsonProperty("line_termination") - @Schema(example = "\\r\\n") - private String lineTermination; -} diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/ImportDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/ImportDto.java index b865f7892cf74fcf1ae4a0feeec3075c87fa5817..043e3bc3eea9c0c438fb34f2e1b9427c0607bb18 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/ImportDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/ImportDto.java @@ -27,16 +27,6 @@ public class ImportDto { @JsonProperty("skip_lines") private Long skipLines; - @JsonProperty("false_element") - private String falseElement; - - @JsonProperty("true_element") - private String trueElement; - - @JsonProperty("null_element") - @Schema(example = "NA") - private String nullElement; - @NotNull @Schema(example = ",") private Character separator; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnCreateDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnCreateDto.java index 03e224bc31072351de2a6501fffe24cdf40ea586..cc9ecca2070714413d2cbc7387447adab659808b 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnCreateDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnCreateDto.java @@ -58,9 +58,6 @@ public class ColumnCreateDto { @JsonProperty("unit_label") private String unitLabel; - @Schema(description = "date format id") - private Long dfid; - @Schema(description = "enum values, only considered when type = ENUM") private List<String> enums; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnDto.java index a506dbca82e9e64d4a0cec4fec12640452f56456..92092fca33d726616ccba63f08a4b4fefbdba1a2 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnDto.java @@ -1,6 +1,5 @@ package at.tuwien.api.database.table.columns; -import at.tuwien.api.container.image.ImageDateDto; import at.tuwien.api.database.ViewDto; import at.tuwien.api.database.table.TableDto; import at.tuwien.api.database.table.columns.concepts.ConceptDto; @@ -59,14 +58,6 @@ public class ColumnDto { @Schema private String alias; - @JsonProperty("date_format") - private ImageDateDto dateFormat; - - @NotNull - @JsonProperty("auto_generated") - @Schema(example = "false") - private Boolean autoGenerated; - @JsonProperty("index_length") private Long indexLength; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnTypeDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnTypeDto.java index 676600c6ff77fb79fd2c19b89d21f826a9cd7d38..d44b25b84ed4c51075ab4c075433750c4aafca42 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnTypeDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnTypeDto.java @@ -49,6 +49,9 @@ public enum ColumnTypeDto { @JsonProperty("set") SET("set"), + @JsonProperty("serial") + SERIAL("serial"), + @JsonProperty("bit") BIT("bit"), diff --git a/dbrepo-metadata-service/entities/pom.xml b/dbrepo-metadata-service/entities/pom.xml index 2fb8efa9e9f07076e4891377c876658dbb04d146..95923c1262a3f9940dbdd7fbd42cbf6e53de7de3 100644 --- a/dbrepo-metadata-service/entities/pom.xml +++ b/dbrepo-metadata-service/entities/pom.xml @@ -6,12 +6,12 @@ <parent> <groupId>at.tuwien</groupId> <artifactId>dbrepo-metadata-service</artifactId> - <version>1.4.5</version> + <version>1.4.7</version> </parent> <artifactId>dbrepo-metadata-service-entities</artifactId> <name>dbrepo-metadata-service-entity</name> - <version>1.4.5</version> + <version>1.4.7</version> <dependencies/> diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/container/Container.java b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/container/Container.java index 302046d035813aa42f43fe211bcafb6a4ca18eed..7545260ce1a83f2a39b7900e9b29de5e0a4bedde 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/container/Container.java +++ b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/container/Container.java @@ -55,6 +55,9 @@ public class Container { @Column private Integer uiPort; + @Column(nullable = false, columnDefinition = "INT DEFAULT 50") + private Integer quota = 50; + @Column private String uiAdditionalFlags; diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/container/image/ContainerImage.java b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/container/image/ContainerImage.java index 568e16e4749c810ef8eae67872d4b2be9e29ddf3..080a843aada9982608cb534c0e24027439e9d9c0 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/container/image/ContainerImage.java +++ b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/container/image/ContainerImage.java @@ -5,8 +5,6 @@ import com.fasterxml.jackson.annotation.JsonFormat; import jakarta.persistence.*; import lombok.*; import org.hibernate.annotations.GenericGenerator; -import org.hibernate.annotations.OnDelete; -import org.hibernate.annotations.OnDeleteAction; import org.springframework.data.annotation.CreatedDate; import org.springframework.data.annotation.LastModifiedDate; import org.springframework.data.jpa.domain.support.AuditingEntityListener; @@ -56,8 +54,8 @@ public class ContainerImage { @Column(nullable = false) private Integer defaultPort; - @OneToMany(fetch = FetchType.LAZY, cascade = {CascadeType.ALL, CascadeType.PERSIST}, mappedBy = "image") - private List<ContainerImageDate> dateFormats; + @Column(nullable = false, unique = true, columnDefinition = "BOOLEAN DEFAULT FALSE") + private Boolean isDefault = false; @ToString.Exclude @OneToMany(fetch = FetchType.LAZY, mappedBy = "image") @@ -72,4 +70,8 @@ public class ContainerImage { @Column(columnDefinition = "TIMESTAMP") private Instant lastModified; + @ToString.Exclude + @OneToMany(fetch = FetchType.LAZY, mappedBy = "image") + private List<DataType> dataTypes; + } diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/container/image/ContainerImageDate.java b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/container/image/ContainerImageDate.java deleted file mode 100644 index 5b370ecc0664fa438e34511d606c75d0219ceb9f..0000000000000000000000000000000000000000 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/container/image/ContainerImageDate.java +++ /dev/null @@ -1,59 +0,0 @@ -package at.tuwien.entities.container.image; - -import com.fasterxml.jackson.annotation.JsonFormat; -import lombok.*; -import org.hibernate.annotations.GenericGenerator; -import org.springframework.data.annotation.CreatedDate; -import org.springframework.data.jpa.domain.support.AuditingEntityListener; - -import jakarta.persistence.*; - -import java.time.Instant; - -@Data -@Entity -@Builder -@ToString -@AllArgsConstructor -@NoArgsConstructor -@EntityListeners(AuditingEntityListener.class) -@EqualsAndHashCode(onlyExplicitlyIncluded = true) -@Table(name = "mdb_images_date", uniqueConstraints = @UniqueConstraint(columnNames = {"database_format"})) -public class ContainerImageDate { - - @Id - @EqualsAndHashCode.Include - @GeneratedValue(generator = "dates-sequence") - @GenericGenerator(name = "dates-sequence", strategy = "increment") - @Column(updatable = false, nullable = false) - private Long id; - - @EqualsAndHashCode.Include - @Column(name = "iid") - private Long iid; - - @ToString.Exclude - @ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.MERGE}) - @JoinColumns({ - @JoinColumn(name = "iid", insertable = false, updatable = false) - }) - private ContainerImage image; - - @Column(name = "example", nullable = false) - private String example; - - @Column(name = "has_time", nullable = false) - private Boolean hasTime; - - @Column(name = "database_format", nullable = false) - private String databaseFormat; - - @Column(name = "unix_format", nullable = false) - private String unixFormat; - - @CreatedDate - @Column(name = "created_at", nullable = false, updatable = false, columnDefinition = "TIMESTAMP") - @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX", timezone = "UTC") - private Instant createdAt; - -} diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/container/image/ContainerImageDateKey.java b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/container/image/ContainerImageDateKey.java deleted file mode 100644 index c5ae9598f7baf4de7df1487561dacca93d4c52f5..0000000000000000000000000000000000000000 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/container/image/ContainerImageDateKey.java +++ /dev/null @@ -1,14 +0,0 @@ -package at.tuwien.entities.container.image; - -import lombok.EqualsAndHashCode; - -import java.io.Serializable; - -@EqualsAndHashCode -public class ContainerImageDateKey implements Serializable { - - private Long id; - - private Long iid; - -} diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/container/image/DataType.java b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/container/image/DataType.java new file mode 100644 index 0000000000000000000000000000000000000000..a98da8d530e550cd12546d3bdfed8ad383461964 --- /dev/null +++ b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/container/image/DataType.java @@ -0,0 +1,77 @@ +package at.tuwien.entities.container.image; + +import jakarta.persistence.*; +import lombok.*; +import org.hibernate.annotations.GenericGenerator; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +@Data +@Entity +@Builder +@ToString +@AllArgsConstructor +@NoArgsConstructor +@EntityListeners(AuditingEntityListener.class) +@EqualsAndHashCode(onlyExplicitlyIncluded = true) +@Table(name = "mdb_image_types") +public class DataType { + + @Id + @EqualsAndHashCode.Include + @GeneratedValue(generator = "image-type-sequence") + @GenericGenerator(name = "image-type-sequence", strategy = "increment") + @Column(updatable = false, nullable = false) + public Long id; + + @Column(name = "display_name", nullable = false) + private String displayName; + + @Column(name = "value", nullable = false, unique = true) + private String value; + + @Column(name = "size_min", nullable = false) + private Integer sizeMin; + + @Column(name = "size_max") + private Integer sizeMax; + + @Column(name = "size_default") + private Integer sizeDefault; + + @Column(name = "size_required", nullable = false) + private Boolean sizeRequired; + + @Column(name = "d_min") + private Integer dMin; + + @Column(name = "d_max") + private Integer dMax; + + @Column(name = "d_default") + private Integer dDefault; + + @Column(name = "d_required", nullable = false) + private Boolean dRequired; + + @Column(nullable = false) + private String documentation; + + @Column(name = "type_hint") + private String typeHint; + + @Column(name = "data_hint") + private String dataHint; + + @Column(name = "is_quoted", nullable = false) + private Boolean quoted; + + @Column(name = "is_buildable", nullable = false) + private Boolean buildable; + + @ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.ALL, CascadeType.PERSIST}) + @JoinColumns({ + @JoinColumn(name = "image_id", referencedColumnName = "id") + }) + private ContainerImage image; + +} diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/Database.java b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/Database.java index 2e154b86973601af8560c6055fe388fd614858a6..17b8308bbaac7e202557208875e566240d928d32 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/Database.java +++ b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/Database.java @@ -122,11 +122,12 @@ public class Database implements Serializable { private List<Table> tables; @ToString.Exclude - @OneToMany(fetch = FetchType.LAZY, cascade = {CascadeType.MERGE, CascadeType.PERSIST}, mappedBy = "database", orphanRemoval = true) + @OrderBy("id DESC") + @OneToMany(fetch = FetchType.LAZY, cascade = {CascadeType.ALL, CascadeType.PERSIST}, mappedBy = "database", orphanRemoval = true) private List<View> views; @ToString.Exclude - @OneToMany(fetch = FetchType.LAZY, cascade = {CascadeType.MERGE, CascadeType.PERSIST}, mappedBy = "database", orphanRemoval = true) + @OneToMany(fetch = FetchType.LAZY, cascade = {CascadeType.ALL, CascadeType.PERSIST}, mappedBy = "database", orphanRemoval = true) private List<DatabaseAccess> accesses; @Column(nullable = false) diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/View.java b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/View.java index 44ffab29592243bc605083aa993e0215ac95475a..28f2ec69c28e84dffcb7c08f9f28941c4dcced54 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/View.java +++ b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/View.java @@ -97,7 +97,7 @@ public class View { @ToString.Exclude @OnDelete(action = OnDeleteAction.CASCADE) @OneToMany(fetch = FetchType.LAZY, cascade = {CascadeType.MERGE, CascadeType.PERSIST}, mappedBy = "view") - @OrderColumn(name = "ordinalPosition") + @OrderBy("ordinalPosition") private List<ViewColumn> columns; @CreatedDate diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/ViewColumn.java b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/ViewColumn.java index eb9b352095bfd1c875cde9fac6db5d45ad8d5e6d..10ac29d8e65eaa15ba592919ac014e452a87a06a 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/ViewColumn.java +++ b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/ViewColumn.java @@ -1,22 +1,21 @@ package at.tuwien.entities.database; -import at.tuwien.entities.container.image.ContainerImageDate; import at.tuwien.entities.database.table.columns.TableColumnType; +import jakarta.persistence.*; import lombok.*; import org.hibernate.annotations.GenericGenerator; import org.springframework.data.jpa.domain.support.AuditingEntityListener; -import jakarta.persistence.*; - @Data @Entity @Builder(toBuilder = true) @ToString @AllArgsConstructor @NoArgsConstructor +@EqualsAndHashCode(onlyExplicitlyIncluded = true) @EntityListeners(AuditingEntityListener.class) @jakarta.persistence.Table(name = "mdb_view_columns", uniqueConstraints = { - @UniqueConstraint(columnNames = {"view_id", "internalName"}) + @UniqueConstraint(columnNames = {"view_id", "internal_name"}) }) public class ViewColumn implements Comparable<ViewColumn> { @@ -27,11 +26,6 @@ public class ViewColumn implements Comparable<ViewColumn> { @Column(updatable = false, nullable = false) private Long id; - @ToString.Exclude - @OneToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "dfid", referencedColumnName = "id") - private ContainerImageDate dateFormat; - @ToString.Exclude @ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.MERGE}) @JoinColumns({ @@ -42,10 +36,7 @@ public class ViewColumn implements Comparable<ViewColumn> { @Column(nullable = false, columnDefinition = "VARCHAR(64)") private String name; - @Column(name = "auto_generated", columnDefinition = "BOOLEAN default false") - private Boolean autoGenerated; - - @Column(nullable = false, columnDefinition = "VARCHAR(64)") + @Column(name = "internal_name", nullable = false, columnDefinition = "VARCHAR(64)") private String internalName; @Column(nullable = false, columnDefinition = "ENUM('CHAR','VARCHAR','BINARY','VARBINARY','TINYBLOB','TINYTEXT','TEXT','BLOB','MEDIUMTEXT','MEDIUMBLOB','LONGTEXT','LONGBLOB','ENUM','SET','BIT','TINYINT','BOOL','SMALLINT','MEDIUMINT','INT','BIGINT','FLOAT','DOUBLE','DECIMAL','DATE','DATETIME','TIMESTAMP','TIME','YEAR')") diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/Table.java b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/Table.java index 9a402201eaf38191213abb609544709d28b516c4..08f6bd9426a8906d4edc4863ecc6f3540cb39448 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/Table.java +++ b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/Table.java @@ -88,12 +88,6 @@ public class Table { }) private Database database; - @ToString.Exclude - @OnDelete(action = OnDeleteAction.CASCADE) - @OneToMany(fetch = FetchType.LAZY, cascade = {CascadeType.MERGE, CascadeType.PERSIST}, mappedBy = "table") - @OrderBy("ordinalPosition") - private List<TableColumn> columns; - @ToString.Exclude @org.springframework.data.annotation.Transient @OneToMany(fetch = FetchType.LAZY) @@ -124,6 +118,12 @@ public class Table { @Column(name = "avg_row_length") private Long avgRowLength; + @ToString.Exclude + @OnDelete(action = OnDeleteAction.CASCADE) + @OneToMany(fetch = FetchType.LAZY, cascade = {CascadeType.MERGE, CascadeType.PERSIST}, mappedBy = "table") + @OrderBy("ordinalPosition") + private List<TableColumn> columns; + @CreatedDate @Column(nullable = false, updatable = false, columnDefinition = "TIMESTAMP") @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX", timezone = "UTC") diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/columns/TableColumn.java b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/columns/TableColumn.java index c869e41637659675e317281fd55092e3b331fc6b..841dbde754a09a5fdd51cec7872ae4c8a4e5e946 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/columns/TableColumn.java +++ b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/columns/TableColumn.java @@ -1,16 +1,14 @@ package at.tuwien.entities.database.table.columns; -import at.tuwien.entities.container.image.ContainerImageDate; import at.tuwien.entities.database.table.Table; import com.fasterxml.jackson.annotation.JsonFormat; +import jakarta.persistence.*; 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 jakarta.persistence.*; - import java.math.BigDecimal; import java.time.Instant; import java.util.List; @@ -24,7 +22,7 @@ import java.util.List; @EqualsAndHashCode(onlyExplicitlyIncluded = true) @EntityListeners(AuditingEntityListener.class) @jakarta.persistence.Table(name = "mdb_columns", uniqueConstraints = { - @UniqueConstraint(columnNames = {"tid", "internalName"}) + @UniqueConstraint(columnNames = {"tID", "internal_name"}) }) @NamedQueries({ @NamedQuery(name = "TableColumn.findAllByDatabaseId", query = "select c from TableColumn c where c.table.database.id = ?1"), @@ -38,11 +36,6 @@ public class TableColumn implements Comparable<TableColumn> { @Column(updatable = false, nullable = false) private Long id; - @ToString.Exclude - @OneToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "dfid", referencedColumnName = "id") - private ContainerImageDate dateFormat; - @ToString.Exclude @ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.MERGE}) @JoinColumns({ @@ -53,10 +46,7 @@ public class TableColumn implements Comparable<TableColumn> { @Column(name = "cname", nullable = false, columnDefinition = "VARCHAR(64)") private String name; - @Column(name = "auto_generated", columnDefinition = "BOOLEAN default false") - private Boolean autoGenerated; - - @Column(nullable = false, columnDefinition = "VARCHAR(64)") + @Column(name = "internal_name", nullable = false, columnDefinition = "VARCHAR(64)") private String internalName; @Column(columnDefinition = "VARCHAR(2048)") @@ -68,7 +58,7 @@ public class TableColumn implements Comparable<TableColumn> { @Transient private String alias; - @Column(name = "datatype", nullable = false, columnDefinition = "ENUM('CHAR','VARCHAR','BINARY','VARBINARY','TINYBLOB','TINYTEXT','TEXT','BLOB','MEDIUMTEXT','MEDIUMBLOB','LONGTEXT','LONGBLOB','ENUM','SET','BIT','TINYINT','BOOL','SMALLINT','MEDIUMINT','INT','BIGINT','FLOAT','DOUBLE','DECIMAL','DATE','DATETIME','TIMESTAMP','TIME','YEAR')") + @Column(name = "Datatype", nullable = false, columnDefinition = "ENUM('CHAR','VARCHAR','BINARY','VARBINARY','TINYBLOB','TINYTEXT','TEXT','BLOB','MEDIUMTEXT','MEDIUMBLOB','LONGTEXT','LONGBLOB','ENUM','SET','SERIAL','BIT','TINYINT','BOOL','SMALLINT','MEDIUMINT','INT','BIGINT','FLOAT','DOUBLE','DECIMAL','DATE','DATETIME','TIMESTAMP','TIME','YEAR')") @Enumerated(EnumType.STRING) private TableColumnType columnType; diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/columns/TableColumnConcept.java b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/columns/TableColumnConcept.java index 080abf87cd022f98f3414087d7b24fe94c0cebd7..e53e69f49808946cff5907f8057bde8923afd9b7 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/columns/TableColumnConcept.java +++ b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/columns/TableColumnConcept.java @@ -50,7 +50,8 @@ public class TableColumnConcept { private Instant created; @ToString.Exclude - @OneToMany(fetch = FetchType.LAZY) + @org.springframework.data.annotation.Transient + @OneToMany(fetch = FetchType.LAZY, cascade = {CascadeType.MERGE}) @JoinTable(name = "mdb_columns_concepts", inverseJoinColumns = { @JoinColumn(name = "cid", referencedColumnName = "id", insertable = false, updatable = false) diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/columns/TableColumnType.java b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/columns/TableColumnType.java index 074620a349fff43977ad585a7e4abe4ad770f39e..7f95c476ddf2d80aa78f773ff5db67aee751b86c 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/columns/TableColumnType.java +++ b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/columns/TableColumnType.java @@ -20,6 +20,7 @@ public enum TableColumnType { LONGBLOB, ENUM, SET, + SERIAL, BIT, TINYINT, BOOL, diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/columns/TableColumnUnit.java b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/columns/TableColumnUnit.java index 21822c5da764886ef9c675d410cd6d74bbaaf4d2..df3950785e4d8a35ef4f8021bfe3a4c34540fbb2 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/columns/TableColumnUnit.java +++ b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/columns/TableColumnUnit.java @@ -49,7 +49,8 @@ public class TableColumnUnit { private Instant created; @ToString.Exclude - @OneToMany(fetch = FetchType.LAZY) + @org.springframework.data.annotation.Transient + @OneToMany(fetch = FetchType.LAZY, cascade = {CascadeType.MERGE}) @JoinTable(name = "mdb_columns_units", inverseJoinColumns = { @JoinColumn(name = "cid", referencedColumnName = "id", insertable = false, updatable = false) diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/foreignKey/ForeignKeyReference.java b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/foreignKey/ForeignKeyReference.java index c63cdd22e6e4ade249ffc41c1305e1d8e7e0c44d..c5f3570099dd5bd12ec641f07e6d2a9f8963b1ce 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/foreignKey/ForeignKeyReference.java +++ b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/foreignKey/ForeignKeyReference.java @@ -32,12 +32,14 @@ public class ForeignKeyReference { @JoinColumn(name = "fkid", referencedColumnName = "fkid", nullable = false) private ForeignKey foreignKey; + @org.springframework.data.annotation.Transient @ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.MERGE}) @JoinColumns({ @JoinColumn(name = "cid", referencedColumnName = "id", nullable = false) }) private TableColumn column; + @org.springframework.data.annotation.Transient @ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.MERGE}) @JoinColumns({ @JoinColumn(name = "rcid", referencedColumnName = "id", nullable = false) diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/primaryKey/PrimaryKey.java b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/primaryKey/PrimaryKey.java index c4ccc379c58d88df8bc2ccc0429bd969d0e5c031..aaa1e5fc8f9102c97294d1f9e53624c5fa3b8e45 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/primaryKey/PrimaryKey.java +++ b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/primaryKey/PrimaryKey.java @@ -27,7 +27,7 @@ public class PrimaryKey { @ToString.Exclude @org.springframework.data.annotation.Transient - @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.MERGE) + @ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.MERGE}) @JoinColumns({ @JoinColumn(name = "tid", referencedColumnName = "id", nullable = false) }) @@ -35,7 +35,7 @@ public class PrimaryKey { @ToString.Exclude @org.springframework.data.annotation.Transient - @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.MERGE) + @ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.MERGE}) @JoinColumns({ @JoinColumn(name = "cid", referencedColumnName = "id", nullable = false) }) diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/unique/Unique.java b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/unique/Unique.java index 25ed2eae5d551896b6836cb6bd5c8bdd36724748..c49fc48eb67b6d5ed3689086a1fba4c75e7a1b6c 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/unique/Unique.java +++ b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/unique/Unique.java @@ -33,13 +33,14 @@ public class Unique { @ToString.Exclude @org.springframework.data.annotation.Transient - @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.MERGE) + @ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.MERGE}) @JoinColumns({ @JoinColumn(name = "tid", referencedColumnName = "id") }) private Table table; - @ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.MERGE) + @org.springframework.data.annotation.Transient + @ManyToMany(fetch = FetchType.LAZY, cascade = {CascadeType.MERGE}) @JoinTable( name = "mdb_constraints_unique_columns", joinColumns = { diff --git a/dbrepo-metadata-service/oai/pom.xml b/dbrepo-metadata-service/oai/pom.xml index 5b37750134eb43f3c077ac3c719c94fcad8d6d77..3239bbc573401cafe3006852109baaa2d04b7ff3 100644 --- a/dbrepo-metadata-service/oai/pom.xml +++ b/dbrepo-metadata-service/oai/pom.xml @@ -6,12 +6,12 @@ <parent> <groupId>at.tuwien</groupId> <artifactId>dbrepo-metadata-service</artifactId> - <version>1.4.5</version> + <version>1.4.7</version> </parent> <artifactId>dbrepo-metadata-service-oai</artifactId> <name>dbrepo-metadata-service-oai</name> - <version>1.4.5</version> + <version>1.4.7</version> <dependencies/> diff --git a/dbrepo-metadata-service/pom.xml b/dbrepo-metadata-service/pom.xml index 0fdc80b428c3120888362bed339edbd9097f0ac4..a2de622dcacd12a615c2d8dc0f536df88ebc87dd 100644 --- a/dbrepo-metadata-service/pom.xml +++ b/dbrepo-metadata-service/pom.xml @@ -11,7 +11,7 @@ <groupId>at.tuwien</groupId> <artifactId>dbrepo-metadata-service</artifactId> <name>dbrepo-metadata-service</name> - <version>1.4.5</version> + <version>1.4.7</version> <description>Service that manages the metadata</description> @@ -27,7 +27,7 @@ <module>report</module> </modules> - <url>https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/</url> + <url>https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.4.7/</url> <developers> <developer> <name>Martin Weise</name> diff --git a/dbrepo-metadata-service/report/pom.xml b/dbrepo-metadata-service/report/pom.xml index 6a7874d4e9352a783ca03711ab1e8efe4eabadea..bfeca5ecff2081adb63d8a1dd9a841665efa67de 100644 --- a/dbrepo-metadata-service/report/pom.xml +++ b/dbrepo-metadata-service/report/pom.xml @@ -6,12 +6,12 @@ <parent> <artifactId>dbrepo-metadata-service</artifactId> <groupId>at.tuwien</groupId> - <version>1.4.5</version> + <version>1.4.7</version> </parent> <artifactId>dbrepo-metadata-service-report</artifactId> <name>dbrepo-metadata-service-report</name> - <version>1.4.5</version> + <version>1.4.7</version> <dependencies> <dependency> diff --git a/dbrepo-metadata-service/repositories/pom.xml b/dbrepo-metadata-service/repositories/pom.xml index b67917715a5c2e1200e3e14884e45cd1ff60c055..9fa9d2b6ab0c073485819dd46f03dbe915eefdee 100644 --- a/dbrepo-metadata-service/repositories/pom.xml +++ b/dbrepo-metadata-service/repositories/pom.xml @@ -6,12 +6,12 @@ <parent> <artifactId>dbrepo-metadata-service</artifactId> <groupId>at.tuwien</groupId> - <version>1.4.5</version> + <version>1.4.7</version> </parent> <artifactId>dbrepo-metadata-service-repositories</artifactId> <name>dbrepo-metadata-service-repositories</name> - <version>1.4.5</version> + <version>1.4.7</version> <dependencies> <dependency> diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ContainerQuotaException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ContainerQuotaException.java new file mode 100644 index 0000000000000000000000000000000000000000..6679775f00473632a2e2e28cd17f3d3303edd0a6 --- /dev/null +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ContainerQuotaException.java @@ -0,0 +1,21 @@ +package at.tuwien.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(code = HttpStatus.LOCKED, reason = "error.container.quota") +public class ContainerQuotaException extends Exception { + + public ContainerQuotaException(String message) { + super(message); + } + + public ContainerQuotaException(String message, Throwable thr) { + super(message, thr); + } + + public ContainerQuotaException(Throwable thr) { + super(thr); + } + +} diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/MetadataMapper.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/MetadataMapper.java index ff5b4f53618e719be0dd8509eb2aaae7aee9769d..0ca5ad870636d98555b1a6a4983de143fde07c51 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/MetadataMapper.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/MetadataMapper.java @@ -4,6 +4,7 @@ import at.tuwien.api.auth.SignupRequestDto; import at.tuwien.api.container.ContainerBriefDto; import at.tuwien.api.container.ContainerCreateDto; import at.tuwien.api.container.ContainerDto; +import at.tuwien.api.container.image.DataTypeDto; import at.tuwien.api.container.image.ImageBriefDto; import at.tuwien.api.container.image.ImageCreateDto; import at.tuwien.api.container.image.ImageDto; @@ -55,6 +56,7 @@ import at.tuwien.api.user.external.ExternalResultType; import at.tuwien.api.user.external.affiliation.ExternalAffiliationDto; import at.tuwien.entities.container.Container; import at.tuwien.entities.container.image.ContainerImage; +import at.tuwien.entities.container.image.DataType; import at.tuwien.entities.database.*; import at.tuwien.entities.database.table.Table; import at.tuwien.entities.database.table.columns.TableColumn; @@ -86,6 +88,14 @@ public interface MetadataMapper { org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(MetadataMapper.class); + @Mappings({ + @Mapping(target = "dMin", source = "DMin"), + @Mapping(target = "dMax", source = "DMax"), + @Mapping(target = "dDefault", source = "DDefault"), + @Mapping(target = "dRequired", source = "DRequired") + }) + DataTypeDto dataTypeToDataTypeDto(DataType data); + BannerMessageDto bannerMessageToBannerMessageDto(BannerMessage data); BannerMessageBriefDto bannerMessageToBannerMessageBriefDto(BannerMessage data); @@ -104,7 +114,8 @@ public interface MetadataMapper { ContainerDto containerToContainerDto(Container data); @Mappings({ - @Mapping(target = "id", source = "id") + @Mapping(target = "id", source = "id"), + @Mapping(target = "count", expression = "java(data.getDatabases().size())"), }) ContainerBriefDto containerToDatabaseContainerBriefDto(Container data); @@ -415,6 +426,9 @@ public interface MetadataMapper { }; } + @Mappings({ + @Mapping(target = "isDefault", source = "isDefault") + }) ContainerImage createImageDtoToContainerImage(ImageCreateDto data); ImageBriefDto containerImageToImageBriefDto(ContainerImage data); @@ -557,7 +571,6 @@ public interface MetadataMapper { ref.getColumn().setDatabaseId(table.getTdbid()); ref.getReferencedColumn().setTableId(fk.getReferencedTable().getId()); ref.getReferencedColumn().setDatabaseId(table.getTdbid()); - log.trace("mapped foreign key part ({}) reference ({})", ref.getColumn().getInternalName(), ref.getReferencedColumn().getInternalName()); }); }); table.getConstraints() @@ -718,7 +731,6 @@ public interface MetadataMapper { @Mapping(target = "columnType", source = "data.type"), @Mapping(target = "isNullAllowed", source = "data.nullAllowed"), @Mapping(target = "name", source = "data.name"), - @Mapping(target = "autoGenerated", expression = "java(false)"), @Mapping(target = "internalName", expression = "java(nameToInternalName(data.getName()))"), }) TableColumn columnCreateDtoToTableColumn(ColumnCreateDto data, ContainerImage image); @@ -755,6 +767,8 @@ public interface MetadataMapper { }) UserDetailsDto userDtoToUserDetailsDto(UserDto data); + User userDtoToUser(at.tuwien.api.keycloak.UserDto data); + /* keep */ @Mappings({ @Mapping(target = "name", expression = "java(userToFullName(data))"), diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/ImageRepository.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/ImageRepository.java index 593a4727180d55b4bc0cb1971c0aecf49313f8cb..23fa40c5be1fd3a6e9e430fafcaccc896e37970d 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/ImageRepository.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/ImageRepository.java @@ -10,8 +10,8 @@ import java.util.Optional; @Repository public interface ImageRepository extends JpaRepository<ContainerImage, Long> { - List<ContainerImage> findAll(); - Optional<ContainerImage> findByNameAndVersion(String name, String version); + Optional<ContainerImage> findByIsDefault(Boolean isDefault); + } diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/TableRepository.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/TableRepository.java new file mode 100644 index 0000000000000000000000000000000000000000..fda9e78ce537b20201ecf88487171a9bb956ea16 --- /dev/null +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/TableRepository.java @@ -0,0 +1,13 @@ +package at.tuwien.repository; + +import at.tuwien.entities.database.table.Table; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +/** + * TO BE USED READONLY + */ +@Repository +public interface TableRepository extends JpaRepository<Table, Long> { + +} diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/ViewRepository.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/ViewRepository.java new file mode 100644 index 0000000000000000000000000000000000000000..de678d90ae99d41a76987be29b1a001929222ceb --- /dev/null +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/ViewRepository.java @@ -0,0 +1,13 @@ +package at.tuwien.repository; + +import at.tuwien.entities.database.View; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +/** + * TO BE USED READONLY + */ +@Repository +public interface ViewRepository extends JpaRepository<View, Long> { + +} diff --git a/dbrepo-metadata-service/rest-service/pom.xml b/dbrepo-metadata-service/rest-service/pom.xml index ab556f9c4521be25c046a5777200ce9ab59cfc6b..1e7c35cbf93b0249c07822b66dcf65b8da26b06e 100644 --- a/dbrepo-metadata-service/rest-service/pom.xml +++ b/dbrepo-metadata-service/rest-service/pom.xml @@ -6,12 +6,12 @@ <parent> <artifactId>dbrepo-metadata-service</artifactId> <groupId>at.tuwien</groupId> - <version>1.4.5</version> + <version>1.4.7</version> </parent> <artifactId>dbrepo-metadata-service-rest-service</artifactId> <name>dbrepo-metadata-service-rest</name> - <version>1.4.5</version> + <version>1.4.7</version> <dependencies> <dependency> diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/AccessEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/AccessEndpoint.java index 9cdcfdedf9e88fd0138e236db6f15afb959ff2dc..f50f916ac4e2a900127244d619814d345c84b809 100644 --- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/AccessEndpoint.java +++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/AccessEndpoint.java @@ -101,18 +101,19 @@ public class AccessEndpoint { data.getType()); final Database database = databaseService.findById(databaseId); final User user = userService.findByUsername(principal.getName()); - if (database.getOwner().equals(user)) { - log.error("Failed to give access to user with id {}: not owner", userId); - throw new NotAllowedException("Failed to give access to user with id " + userId + ": not owner"); + if (!database.getOwner().equals(user)) { + log.error("Failed to create access: not owner"); + throw new NotAllowedException("Failed to create access: not owner"); } + final User otherUser = userService.findById(userId); try { - accessService.find(database, user); - log.error("Failed to give access to user with id {}: already has access", userId); - throw new NotAllowedException("Failed to give access to user with id " + userId + ": already has access"); + accessService.find(database, otherUser); + log.error("Failed to create access to user with id {}: already has access", userId); + throw new NotAllowedException("Failed to create access to user with id " + userId + ": already has access"); } catch (AccessNotFoundException e) { /* ignore */ } - accessService.create(database, user, data.getType()); + accessService.create(database, otherUser, data.getType()); return ResponseEntity.accepted() .build(); } @@ -163,12 +164,13 @@ public class AccessEndpoint { data.getType()); final Database database = databaseService.findById(databaseId); final User user = userService.findByUsername(principal.getName()); - if (database.getOwner().equals(user)) { - log.error("Failed to give access to user with id {}: not owner", userId); - throw new NotAllowedException("Failed to give access to user with id " + userId + ": not owner"); + if (!database.getOwner().equals(user)) { + log.error("Failed to update access: not owner"); + throw new NotAllowedException("Failed to update access: not owner"); } - accessService.find(database, user); - accessService.update(database, user, data.getType()); + final User otherUser = userService.findById(userId); + accessService.find(database, otherUser); + accessService.update(database, otherUser, data.getType()); return ResponseEntity.accepted() .build(); } @@ -211,8 +213,8 @@ public class AccessEndpoint { log.trace("principal is allowed to check foreign user access"); } final Database database = databaseService.findById(databaseId); - final User user = userService.findById(userId); - final DatabaseAccess access = accessService.find(database, user); + final User otherUser = userService.findById(userId); + final DatabaseAccess access = accessService.find(database, otherUser); final DatabaseAccessDto dto = databaseMapper.databaseAccessToDatabaseAccessDto(access); log.trace("check access resulted in dto {}", dto); return ResponseEntity.ok(dto); @@ -263,11 +265,12 @@ public class AccessEndpoint { final Database database = databaseService.findById(databaseId); final User user = userService.findByUsername(principal.getName()); if (!database.getOwner().equals(user)) { - log.error("Failed to revoke access to user with id {}: not owner", user.getId()); - throw new NotAllowedException("Failed to revoke access to user with id " + user.getId() + ": not owner"); + log.error("Failed to revoke access: not owner"); + throw new NotAllowedException("Failed to revoke access: not owner"); } - accessService.find(database, user); - accessService.delete(database, user); + final User otherUser = userService.findById(userId); + accessService.find(database, otherUser); + accessService.delete(database, otherUser); return ResponseEntity.accepted() .build(); } diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ContainerEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ContainerEndpoint.java index 294d471e8fefe4ccafcf06f5aac47e23fce6f757..62319662e24b78f9e456d1d0cabd8fd79639c85f 100644 --- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ContainerEndpoint.java +++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ContainerEndpoint.java @@ -27,7 +27,6 @@ import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.security.core.Authentication; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.*; @@ -66,11 +65,11 @@ public class ContainerEndpoint { }) public ResponseEntity<List<ContainerBriefDto>> findAll(@RequestParam(required = false) Integer limit) { log.debug("endpoint find all containers, limit={}", limit); - final List<Container> containers = containerService.getAll(limit); - final List<ContainerBriefDto> dtos = containers.stream() + final List<ContainerBriefDto> dtos = containerService.getAll(limit) + .stream() .map(metadataMapper::containerToDatabaseContainerBriefDto) .collect(Collectors.toList()); - log.trace("find all containers resulted in containers {}", dtos); + log.debug("find all containers resulted in {} container(s)", dtos.size()); return ResponseEntity.ok() .body(dtos); } diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/DatabaseEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/DatabaseEndpoint.java index 8be62ea5c400719b31764b0b931a329481b75018..d5c316fed960a8600352df7201871a370654c021 100644 --- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/DatabaseEndpoint.java +++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/DatabaseEndpoint.java @@ -2,6 +2,8 @@ package at.tuwien.endpoints; import at.tuwien.api.database.*; import at.tuwien.api.error.ApiErrorDto; +import at.tuwien.entities.container.Container; +import at.tuwien.entities.container.image.DataType; import at.tuwien.entities.database.Database; import at.tuwien.entities.database.DatabaseAccess; import at.tuwien.entities.user.User; @@ -45,15 +47,18 @@ public class DatabaseEndpoint { private final MetadataMapper databaseMapper; private final StorageService storageService; private final DatabaseService databaseService; + private final ContainerService containerService; @Autowired public DatabaseEndpoint(UserService userService, AccessService accessService, MetadataMapper databaseMapper, - StorageService storageService, DatabaseService databaseService) { + StorageService storageService, DatabaseService databaseService, + ContainerService containerService) { this.userService = userService; this.accessService = accessService; this.databaseMapper = databaseMapper; this.storageService = storageService; this.databaseService = databaseService; + this.containerService = containerService; } @RequestMapping(method = {RequestMethod.GET, RequestMethod.HEAD}) @@ -127,6 +132,11 @@ public class DatabaseEndpoint { content = {@Content( mediaType = "application/json", schema = @Schema(implementation = ApiErrorDto.class))}), + @ApiResponse(responseCode = "423", + description = "Database quota exceeded", + content = {@Content( + mediaType = "application/json", + schema = @Schema(implementation = ApiErrorDto.class))}), @ApiResponse(responseCode = "502", description = "Connection to search service failed", content = {@Content( @@ -141,10 +151,15 @@ public class DatabaseEndpoint { public ResponseEntity<DatabaseDto> create(@Valid @RequestBody DatabaseCreateDto data, @NotNull Principal principal) throws DataServiceException, DataServiceConnectionException, UserNotFoundException, DatabaseNotFoundException, ContainerNotFoundException, - SearchServiceException, SearchServiceConnectionException { + SearchServiceException, SearchServiceConnectionException, ContainerQuotaException { log.debug("endpoint create database, data.name={}", data.getName()); + final Container container = containerService.find(data.getCid()); + if (container.getDatabases().size() + 1 > container.getQuota()) { + log.error("Failed to create database: quota of {} exceeded", container.getQuota()); + throw new ContainerQuotaException("Failed to create database: quota of " + container.getQuota() + " exceeded"); + } final User user = userService.findByUsername(principal.getName()); - final Database database = databaseService.create(data, user); + final Database database = databaseService.create(container, data, user); final DatabaseDto dto = databaseMapper.customDatabaseToDatabaseDto(database); return ResponseEntity.status(HttpStatus.CREATED) .body(dto); diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/TableEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/TableEndpoint.java index 9b4fb753a3fa8d96629c903b427688e630ee8a16..0e74f02f8361f5ac80b1745e4258da6b1cd809eb 100644 --- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/TableEndpoint.java +++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/TableEndpoint.java @@ -3,9 +3,7 @@ package at.tuwien.endpoints; import at.tuwien.api.database.table.TableBriefDto; import at.tuwien.api.database.table.TableCreateDto; import at.tuwien.api.database.table.TableDto; -import at.tuwien.api.database.table.columns.ColumnCreateDto; import at.tuwien.api.database.table.columns.ColumnDto; -import at.tuwien.api.database.table.columns.ColumnTypeDto; import at.tuwien.api.database.table.columns.concepts.ColumnSemanticsUpdateDto; import at.tuwien.api.error.ApiErrorDto; import at.tuwien.entities.database.Database; @@ -14,7 +12,10 @@ import at.tuwien.entities.database.table.columns.TableColumn; import at.tuwien.entities.user.User; import at.tuwien.exception.*; import at.tuwien.mapper.MetadataMapper; -import at.tuwien.service.*; +import at.tuwien.service.DatabaseService; +import at.tuwien.service.EntityService; +import at.tuwien.service.TableService; +import at.tuwien.service.UserService; import at.tuwien.utils.UserUtil; import at.tuwien.validation.EndpointValidator; import io.micrometer.observation.annotation.Observed; @@ -37,7 +38,7 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.*; import java.security.Principal; -import java.util.*; +import java.util.List; import java.util.stream.Collectors; @Log4j2 @@ -259,15 +260,6 @@ public class TableEndpoint { final Database database = databaseService.findById(databaseId); endpointValidator.validateOnlyAccess(database, principal, true); endpointValidator.validateColumnCreateConstraints(data); - final List<ColumnCreateDto> failedDateColumns = data.getColumns() - .stream() - .filter(column -> List.of(ColumnTypeDto.DATE, ColumnTypeDto.DATETIME, ColumnTypeDto.TIME, ColumnTypeDto.TIMESTAMP).contains(column.getType())) - .filter(column -> Objects.isNull(column.getDfid())) - .toList(); - if (!failedDateColumns.isEmpty()) { - log.error("Failed to create table: date column(s) {} do not contain date format id", failedDateColumns.stream().map(ColumnCreateDto::getName).toList()); - throw new MalformedException("Failed to create table: date column(s) " + failedDateColumns.stream().map(ColumnCreateDto::getName).toList() + " do not contain date format id"); - } final Table table = tableService.createTable(database, data, principal); final TableDto dto = metadataMapper.customTableToTableDto(table); log.info("Created table with id {}", dto.getId()); diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/UserEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/UserEndpoint.java index 4be54d5edd1ed39168b97a00177d87d09a7a87ee..34082d18c14b4c6c92b9d353bedbb8892b571fe8 100644 --- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/UserEndpoint.java +++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/UserEndpoint.java @@ -5,7 +5,10 @@ import at.tuwien.api.auth.RefreshTokenRequestDto; import at.tuwien.api.auth.SignupRequestDto; import at.tuwien.api.error.ApiErrorDto; import at.tuwien.api.keycloak.TokenDto; -import at.tuwien.api.user.*; +import at.tuwien.api.user.UserBriefDto; +import at.tuwien.api.user.UserDto; +import at.tuwien.api.user.UserPasswordDto; +import at.tuwien.api.user.UserUpdateDto; import at.tuwien.entities.database.Database; import at.tuwien.entities.user.User; import at.tuwien.exception.*; @@ -26,6 +29,7 @@ import jakarta.validation.Valid; import jakarta.validation.constraints.NotNull; import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; @@ -68,13 +72,21 @@ public class UserEndpoint { mediaType = "application/json", array = @ArraySchema(schema = @Schema(implementation = UserBriefDto.class)))}), }) - public ResponseEntity<List<UserBriefDto>> findAll() { - log.debug("endpoint find all users"); - final List<UserBriefDto> users = userService.findAll() - .stream() - .map(userMapper::userToUserBriefDto) - .toList(); - return ResponseEntity.ok(users); + public ResponseEntity<List<UserBriefDto>> findAll(@RequestParam(required = false) String username) { + log.debug("endpoint find all users, username={}", username); + if (username == null) { + return ResponseEntity.ok(userService.findAll() + .stream() + .map(userMapper::userToUserBriefDto) + .toList()); + } + try { + log.trace("filter by username: {}", username); + return ResponseEntity.ok(List.of(userMapper.userToUserBriefDto(userService.findByUsername(username)))); + } catch (UserNotFoundException e) { + log.trace("filter by username {} failed: return empty list", username); + return ResponseEntity.ok(List.of()); + } } @PostMapping @@ -276,7 +288,13 @@ public class UserEndpoint { } } final UserDto dto = userMapper.userToUserDto(user); - return ResponseEntity.ok() + final HttpHeaders headers = new HttpHeaders(); + if (UserUtil.isSystem(principal)) { + headers.set("X-Username", user.getUsername()); + headers.set("X-Password", user.getMariadbPassword()); + } + return ResponseEntity.status(HttpStatus.OK) + .headers(headers) .body(dto); } diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/handlers/ApiExceptionHandler.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/handlers/ApiExceptionHandler.java index f6764895556ac07fe0321ae3e4a580f17e873d54..bf655f071abee0fdd5fc390b76402e3165d04c37 100644 --- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/handlers/ApiExceptionHandler.java +++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/handlers/ApiExceptionHandler.java @@ -79,6 +79,13 @@ public class ApiExceptionHandler extends ResponseEntityExceptionHandler { return generic_handle(e.getClass(), e.getLocalizedMessage()); } + @Hidden + @ResponseStatus(code = HttpStatus.LOCKED) + @ExceptionHandler(ContainerQuotaException.class) + public ResponseEntity<ApiErrorDto> handle(ContainerQuotaException e) { + return generic_handle(e.getClass(), e.getLocalizedMessage()); + } + @Hidden @ResponseStatus(code = HttpStatus.FORBIDDEN) @ExceptionHandler(CredentialsInvalidException.class) diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/validation/EndpointValidator.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/validation/EndpointValidator.java index 7f05bf84a58ad90788476850fed0765394f80ae2..75f76d440a4d059dfe9c918952519976aa5cbdb3 100644 --- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/validation/EndpointValidator.java +++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/validation/EndpointValidator.java @@ -21,12 +21,19 @@ import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; import java.security.Principal; -import java.util.*; +import java.util.List; +import java.util.Objects; +import java.util.Optional; @Log4j2 @Component public class EndpointValidator { + public static final List<ColumnTypeDto> NEED_NOTHING = List.of(ColumnTypeDto.BOOL, ColumnTypeDto.SERIAL); + public static final List<ColumnTypeDto> NEED_SIZE = List.of(ColumnTypeDto.VARCHAR, ColumnTypeDto.BINARY, ColumnTypeDto.VARBINARY); + public static final List<ColumnTypeDto> CAN_HAVE_SIZE = List.of(ColumnTypeDto.CHAR, ColumnTypeDto.VARCHAR, ColumnTypeDto.BINARY, ColumnTypeDto.VARBINARY, ColumnTypeDto.BIT, ColumnTypeDto.TINYINT, ColumnTypeDto.SMALLINT, ColumnTypeDto.MEDIUMINT, ColumnTypeDto.INT); + public static final List<ColumnTypeDto> CAN_HAVE_SIZE_AND_D = List.of(ColumnTypeDto.DOUBLE, ColumnTypeDto.DECIMAL); + private final UserService userService; private final AccessService accessService; @@ -68,46 +75,45 @@ public class EndpointValidator { if (data == null) { throw new MalformedException("Validation failed: table data is null"); } - final List<ColumnTypeDto> needSize = List.of(ColumnTypeDto.CHAR, ColumnTypeDto.VARCHAR, ColumnTypeDto.BINARY, ColumnTypeDto.VARBINARY, ColumnTypeDto.BIT, ColumnTypeDto.TINYINT, ColumnTypeDto.SMALLINT, ColumnTypeDto.MEDIUMINT, ColumnTypeDto.INT); - final List<ColumnTypeDto> needSizeAndD = List.of(ColumnTypeDto.DOUBLE, ColumnTypeDto.DECIMAL); - final List<ColumnTypeDto> needDateFormat = List.of(ColumnTypeDto.DATETIME, ColumnTypeDto.TIMESTAMP, ColumnTypeDto.TIME); /* check size */ final Optional<ColumnCreateDto> optional0 = data.getColumns() .stream() .filter(c -> Objects.isNull(c.getSize())) - .filter(c -> needSize.contains(c.getType())) + .filter(c -> NEED_SIZE.contains(c.getType())) .findFirst(); if (optional0.isPresent()) { - log.error("Validation failed: column {} needs size parameter", optional0.get().getName()); - throw new MalformedException("Validation failed: column " + optional0.get().getName() + " needs size parameter"); + log.error("Validation failed: column {} need size parameter", optional0.get().getName()); + throw new MalformedException("Validation failed: column " + optional0.get().getName() + " need size parameter"); } - /* check size and d */ - final Optional<ColumnCreateDto> optional1 = data.getColumns() + final Optional<ColumnCreateDto> optional0a = data.getColumns() .stream() - .filter(c -> needSizeAndD.contains(c.getType())) - .filter(c -> Objects.isNull(c.getSize()) || Objects.isNull(c.getD())) + .filter(c -> !Objects.isNull(c.getSize())) + .filter(c -> CAN_HAVE_SIZE.contains(c.getType()) || CAN_HAVE_SIZE_AND_D.contains(c.getType())) + .filter(c -> c.getSize() < 0) .findFirst(); - if (optional1.isPresent()) { - log.error("Validation failed: column {} needs size and d parameter", optional1.get().getName()); - throw new MalformedException("Validation failed: column " + optional1.get().getName() + " needs size and d parameter"); + if (optional0a.isPresent()) { + log.error("Validation failed: column {} needs positive size parameter", optional0a.get().getName()); + throw new MalformedException("Validation failed: column " + optional0a.get().getName() + " needs positive size parameter"); } - final Optional<ColumnCreateDto> optional1a = data.getColumns() + final Optional<ColumnCreateDto> optional0b = data.getColumns() .stream() - .filter(c -> needSizeAndD.contains(c.getType())) - .filter(c -> c.getSize() > 65 || c.getD() > 38) + .filter(c -> !Objects.isNull(c.getD())) + .filter(c -> CAN_HAVE_SIZE_AND_D.contains(c.getType())) + .filter(c -> c.getD() < 0) .findFirst(); - if (optional1a.isPresent()) { - log.error("Validation failed: column {} needs size (max 65) and d (max 30)", optional1a.get().getName()); - throw new MalformedException("Validation failed: column " + optional1a.get().getName() + " needs size (max 65) and d (max 30)"); + if (optional0b.isPresent()) { + log.error("Validation failed: column {} needs positive d parameter", optional0b.get().getName()); + throw new MalformedException("Validation failed: column " + optional0b.get().getName() + " needs positive d parameter"); } - final Optional<ColumnCreateDto> optional1b = data.getColumns() + /* check size and d */ + final Optional<ColumnCreateDto> optional1 = data.getColumns() .stream() - .filter(c -> needSizeAndD.contains(c.getType())) - .filter(c -> c.getSize() < c.getD()) + .filter(c -> Objects.isNull(c.getSize()) ^ Objects.isNull(c.getD())) + .filter(c -> CAN_HAVE_SIZE_AND_D.contains(c.getType())) .findFirst(); - if (optional1b.isPresent()) { - log.error("Validation failed: column {} needs size >= d", optional1b.get().getName()); - throw new MalformedException("Validation failed: column " + optional1b.get().getName() + " needs size >= d"); + if (optional1.isPresent()) { + log.error("Validation failed: column {} either needs both size and d parameter or none (use default)", optional1.get().getName()); + throw new MalformedException("Validation failed: column " + optional1.get().getName() + " either needs both size and d parameter or none (use default)"); } /* check enum */ final Optional<ColumnCreateDto> optional2 = data.getColumns() @@ -129,15 +135,34 @@ public class EndpointValidator { log.error("Validation failed: column {} needs at least 1 allowed set value", optional3.get().getName()); throw new MalformedException("Validation failed: column " + optional3.get().getName() + " needs at least 1 allowed set value"); } - /* check date */ - final Optional<ColumnCreateDto> optional4 = data.getColumns() + /* check serial */ + final List<ColumnCreateDto> list4a = data.getColumns() + .stream() + .filter(c -> c.getType().equals(ColumnTypeDto.SERIAL)) + .toList(); + if (list4a.size() > 1) { + log.error("Validation failed: only one column of type serial allowed"); + throw new MalformedException("Validation failed: only one column of type serial allowed"); + } + final Optional<ColumnCreateDto> optional4a = data.getColumns() + .stream() + .filter(c -> c.getType().equals(ColumnTypeDto.SERIAL)) + .filter(ColumnCreateDto::getNullAllowed) + .findFirst(); + if (optional4a.isPresent()) { + log.error("Validation failed: column {} type serial demands non-null", optional4a.get().getName()); + throw new MalformedException("Validation failed: column " + optional4a.get().getName() + " type serial demands non-null"); + } + final Optional<ColumnCreateDto> optional4b = data.getColumns() .stream() - .filter(c -> needDateFormat.contains(c.getType())) - .filter(c -> Objects.isNull(c.getDfid())) + .filter(c -> c.getType().equals(ColumnTypeDto.SERIAL) && data.getConstraints() + .getUniques() + .stream() + .noneMatch(uk -> uk.size() == 1 && uk.contains(c.getName()))) .findFirst(); - if (optional4.isPresent()) { - log.error("Validation failed: column {} needs a format", optional4.get().getName()); - throw new MalformedException("Validation failed: column " + optional4.get().getName() + " needs a format"); + if (optional4b.isPresent()) { + log.error("Validation failed: column {} type serial demands a unique constraint", optional4b.get().getName()); + throw new MalformedException("Validation failed: column " + optional4b.get().getName() + " type serial demands a unique constraint"); } } diff --git a/dbrepo-metadata-service/rest-service/src/main/resources/application-local.yml b/dbrepo-metadata-service/rest-service/src/main/resources/application-local.yml index e2c9df6a59d8454661ca42b72617f2b67d6c1492..793a2b6021a270dfd6b23971e40675889b3e4980 100644 --- a/dbrepo-metadata-service/rest-service/src/main/resources/application-local.yml +++ b/dbrepo-metadata-service/rest-service/src/main/resources/application-local.yml @@ -66,7 +66,7 @@ dbrepo: searchService: http://localhost analyseService: http://localhost dataService: http://localhost:9093 - brokerService: http://localhost/admin/broker + brokerService: http://localhost:15672 authService: http://localhost/api/auth storageService: http://localhost/api/storage rorService: https://api.ror.org diff --git a/dbrepo-metadata-service/rest-service/src/main/resources/datatypes.json b/dbrepo-metadata-service/rest-service/src/main/resources/datatypes.json new file mode 100644 index 0000000000000000000000000000000000000000..3779d12cbe32b67fa163cf6b0285b9e01f7dc681 --- /dev/null +++ b/dbrepo-metadata-service/rest-service/src/main/resources/datatypes.json @@ -0,0 +1,15 @@ +[ + { + "name": "", + "size": { + "min": 0, + "required": true + }, + "d": { + "required": false + }, + "documentation": "https://mariadb.com/kb/en/bigint/", + "quoted": false, + "buildable": true + } +] \ No newline at end of file diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/AccessEndpointUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/AccessEndpointUnitTest.java index 69d817afb763fa47b878b71fb315bb8dbb02f750..7c6061ed1e663c27d9f2a72bc64e309eaee0ffc1 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/AccessEndpointUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/AccessEndpointUnitTest.java @@ -1,17 +1,18 @@ package at.tuwien.endpoints; -import at.tuwien.mapper.MetadataMapper; -import at.tuwien.test.AbstractUnitTest; import at.tuwien.api.database.AccessTypeDto; import at.tuwien.api.database.DatabaseAccessDto; import at.tuwien.entities.database.Database; import at.tuwien.entities.database.DatabaseAccess; import at.tuwien.entities.user.User; import at.tuwien.exception.*; +import at.tuwien.mapper.MetadataMapper; import at.tuwien.repository.DatabaseRepository; import at.tuwien.repository.UserRepository; import at.tuwien.service.AccessService; +import at.tuwien.test.AbstractUnitTest; import lombok.extern.log4j.Log4j2; +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; @@ -51,13 +52,18 @@ public class AccessEndpointUnitTest extends AbstractUnitTest { @Autowired private MetadataMapper metadataMapper; + @BeforeEach + public void beforeEach() { + genesis(); + } + @Test @WithAnonymousUser public void create_anonymous_fails() { /* test */ assertThrows(org.springframework.security.access.AccessDeniedException.class, () -> { - generic_create(null, USER_2_ID, null, null); + generic_create(null, null, null, null); }); } @@ -67,7 +73,7 @@ public class AccessEndpointUnitTest extends AbstractUnitTest { /* test */ assertThrows(org.springframework.security.access.AccessDeniedException.class, () -> { - generic_create(USER_2_PRINCIPAL, USER_4_ID, USER_4_USERNAME, USER_4); + generic_create(USER_2_PRINCIPAL, USER_2, USER_4_ID, USER_4); }); } @@ -82,7 +88,7 @@ public class AccessEndpointUnitTest extends AbstractUnitTest { .thenReturn(DATABASE_1_USER_1_READ_ACCESS); /* test */ - generic_create(USER_2_PRINCIPAL, USER_2_ID, USER_2_USERNAME, USER_2); + generic_create(USER_1_PRINCIPAL, USER_1, USER_2_ID, USER_2); } @Test @@ -129,7 +135,7 @@ public class AccessEndpointUnitTest extends AbstractUnitTest { /* test */ assertThrows(org.springframework.security.access.AccessDeniedException.class, () -> { - generic_update(null, USER_4_USERNAME, USER_4, null, null); + generic_update(null, null, null, null, null); }); } @@ -138,8 +144,8 @@ public class AccessEndpointUnitTest extends AbstractUnitTest { public void update_hasRoleNoAccess_fails() { /* test */ - assertThrows(NotAllowedException.class, () -> { - generic_update(null, USER_4_USERNAME, USER_4, USER_1_PRINCIPAL, USER_1); + assertThrows(AccessNotFoundException.class, () -> { + generic_update(USER_1_PRINCIPAL, USER_1, USER_4_ID, USER_4, null); }); } @@ -149,7 +155,7 @@ public class AccessEndpointUnitTest extends AbstractUnitTest { /* test */ assertThrows(org.springframework.security.access.AccessDeniedException.class, () -> { - generic_update(null, USER_4_USERNAME, USER_4, USER_4_PRINCIPAL, USER_4); + generic_update(USER_4_PRINCIPAL, USER_4, USER_1_ID, USER_1, null); }); } @@ -165,7 +171,7 @@ public class AccessEndpointUnitTest extends AbstractUnitTest { .update(eq(DATABASE_1), eq(USER_2), any(AccessTypeDto.class)); /* test */ - generic_update(DATABASE_1_USER_2_WRITE_OWN_ACCESS, USER_2_USERNAME, USER_2, USER_2_PRINCIPAL, USER_2); + generic_update(USER_1_PRINCIPAL, USER_1, USER_2_ID, USER_2, DATABASE_1_USER_2_WRITE_OWN_ACCESS); } @Test @@ -174,7 +180,7 @@ public class AccessEndpointUnitTest extends AbstractUnitTest { /* test */ assertThrows(org.springframework.security.access.AccessDeniedException.class, () -> { - generic_revoke(USER_1_PRINCIPAL, USER_1); + generic_revoke(null, null, USER_1_ID, USER_1); }); } @@ -184,7 +190,7 @@ public class AccessEndpointUnitTest extends AbstractUnitTest { /* test */ assertThrows(org.springframework.security.access.AccessDeniedException.class, () -> { - generic_revoke(USER_4_PRINCIPAL, USER_4); + generic_revoke(USER_4_PRINCIPAL, USER_4, USER_1_ID, USER_1); }); } @@ -200,14 +206,14 @@ public class AccessEndpointUnitTest extends AbstractUnitTest { .delete(DATABASE_1, USER_2); /* test */ - generic_revoke(USER_1_PRINCIPAL, USER_1); + generic_revoke(USER_1_PRINCIPAL, USER_1, USER_2_ID, USER_2); } /* ################################################################################################### */ /* ## GENERIC TEST CASES ## */ /* ################################################################################################### */ - protected void generic_create(Principal principal, UUID userId, String username, User user) + protected void generic_create(Principal principal, User principalUser, UUID userId, User user) throws NotAllowedException, DataServiceException, DataServiceConnectionException, UserNotFoundException, DatabaseNotFoundException, AccessNotFoundException, SearchServiceException, SearchServiceConnectionException { @@ -218,11 +224,18 @@ public class AccessEndpointUnitTest extends AbstractUnitTest { doThrow(AccessNotFoundException.class) .when(accessService) .find(DATABASE_1, user); + if (principalUser != null) { + when(userRepository.findByUsername(principal.getName())) + .thenReturn(Optional.of(principalUser)); + } else { + when(userRepository.findByUsername(anyString())) + .thenReturn(Optional.empty()); + } if (user != null) { - when(userRepository.findByUsername(username)) + when(userRepository.findById(userId)) .thenReturn(Optional.of(user)); } else { - when(userRepository.findByUsername(anyString())) + when(userRepository.findById(any(UUID.class))) .thenReturn(Optional.empty()); } @@ -268,61 +281,62 @@ public class AccessEndpointUnitTest extends AbstractUnitTest { } } - protected void generic_update(DatabaseAccess access, String otherUsername, User otherUser, Principal principal, - User user) throws NotAllowedException, DataServiceException, DataServiceConnectionException, - AccessNotFoundException, UserNotFoundException, DatabaseNotFoundException, SearchServiceException, - SearchServiceConnectionException { + protected void generic_update(Principal principal, User principalUser, UUID userId, User user, + DatabaseAccess access) throws NotAllowedException, DataServiceException, + DataServiceConnectionException, AccessNotFoundException, UserNotFoundException, DatabaseNotFoundException, + SearchServiceException, SearchServiceConnectionException { /* mock */ when(databaseRepository.findById(DATABASE_1_ID)) .thenReturn(Optional.of(DATABASE_1)); if (access != null) { - log.trace("mock access {} for user with id {} for database with id {}", access.getType(), USER_1_ID, DATABASE_1_ID); - when(accessService.find(DATABASE_1, USER_1)) + log.trace("mock access {} for user with id {} for database with id {}", access.getType(), userId, DATABASE_1_ID); + when(accessService.find(DATABASE_1, user)) .thenReturn(access); } else { - log.trace("mock no access for user with id {} for database with id {}", USER_1_ID, DATABASE_1_ID); + log.trace("mock no access for user with id {} for database with id {}", userId, DATABASE_1_ID); doThrow(AccessNotFoundException.class) .when(accessService) - .find(DATABASE_1, USER_1); + .find(DATABASE_1, user); } - if (otherUsername != null) { - when(userRepository.findByUsername(otherUsername)) - .thenReturn(Optional.of(otherUser)); + if (userId != null) { + when(userRepository.findById(userId)) + .thenReturn(Optional.of(user)); } else { - when(userRepository.findByUsername(anyString())) + when(userRepository.findById(any(UUID.class))) .thenReturn(Optional.empty()); } if (principal != null) { when(userRepository.findByUsername(principal.getName())) - .thenReturn(Optional.of(user)); + .thenReturn(Optional.of(principalUser)); } else { when(userRepository.findByUsername(anyString())) .thenReturn(Optional.empty()); } /* test */ - final ResponseEntity<?> response = accessEndpoint.update(DATABASE_1_ID, USER_1_ID, UPDATE_DATABASE_ACCESS_READ_DTO, principal); + final ResponseEntity<?> response = accessEndpoint.update(DATABASE_1_ID, userId, UPDATE_DATABASE_ACCESS_READ_DTO, principal); assertEquals(HttpStatus.ACCEPTED, response.getStatusCode()); assertNull(response.getBody()); } - protected void generic_revoke(Principal principal, User user) throws DataServiceConnectionException, - NotAllowedException, DataServiceException, UserNotFoundException, DatabaseNotFoundException, - AccessNotFoundException, SearchServiceException, SearchServiceConnectionException { + protected void generic_revoke(Principal principal, User principalUser, UUID userId, User user) + throws DataServiceConnectionException, NotAllowedException, DataServiceException, UserNotFoundException, + DatabaseNotFoundException, AccessNotFoundException, SearchServiceException, + SearchServiceConnectionException { /* mock */ - when(accessService.find(any(Database.class), eq(user))) - .thenReturn(DATABASE_1_USER_1_READ_ACCESS); when(databaseRepository.findById(DATABASE_1_ID)) .thenReturn(Optional.of(DATABASE_1)); if (principal != null) { when(userRepository.findByUsername(principal.getName())) - .thenReturn(Optional.of(user)); + .thenReturn(Optional.of(principalUser)); } + when(userRepository.findById(userId)) + .thenReturn(Optional.of(user)); /* test */ - final ResponseEntity<?> response = accessEndpoint.revoke(DATABASE_1_ID, USER_1_ID, principal); + final ResponseEntity<?> response = accessEndpoint.revoke(DATABASE_1_ID, userId, principal); assertEquals(HttpStatus.ACCEPTED, response.getStatusCode()); assertNull(response.getBody()); } diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/ActuatorComponentTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/ActuatorComponentTest.java index 238dec0db1736eccca0976a0d0c89badabd58dcd..78b7f086c300b546c808ed161abef2e3712e64c3 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/ActuatorComponentTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/ActuatorComponentTest.java @@ -2,6 +2,7 @@ package at.tuwien.endpoints; import at.tuwien.test.AbstractUnitTest; import lombok.extern.log4j.Log4j2; +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; @@ -24,6 +25,11 @@ public class ActuatorComponentTest extends AbstractUnitTest { @Autowired private MockMvc mockMvc; + @BeforeEach + public void beforeEach() { + genesis(); + } + @Test public void actuatorInfo_succeeds() throws Exception { this.mockMvc.perform(get("/actuator/info")) diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/ConceptEndpointUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/ConceptEndpointUnitTest.java index 6698be6995ac00573e348274e5cb411f08755023..d48317f119cbbdf51087b16fc4c8df999bd519bb 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/ConceptEndpointUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/ConceptEndpointUnitTest.java @@ -4,6 +4,7 @@ import at.tuwien.test.AbstractUnitTest; import at.tuwien.api.database.table.columns.concepts.ConceptDto; import at.tuwien.service.ConceptService; import lombok.extern.log4j.Log4j2; +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; @@ -31,6 +32,11 @@ public class ConceptEndpointUnitTest extends AbstractUnitTest { @Autowired private ConceptEndpoint conceptEndpoint; + @BeforeEach + public void beforeEach() { + genesis(); + } + @Test @WithAnonymousUser public void findAllConcepts_anonymous_succeeds() { diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/ContainerEndpointUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/ContainerEndpointUnitTest.java index 7706e185bd3721fdddec7daed15ce8df628b0bad..ab3f4485b2cf35134c2d0ee126ee30af04636165 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/ContainerEndpointUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/ContainerEndpointUnitTest.java @@ -8,6 +8,7 @@ import at.tuwien.entities.container.Container; import at.tuwien.exception.*; import at.tuwien.service.impl.ContainerServiceImpl; import lombok.extern.log4j.Log4j2; +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; @@ -37,6 +38,11 @@ public class ContainerEndpointUnitTest extends AbstractUnitTest { @Autowired private ContainerEndpoint containerEndpoint; + @BeforeEach + public void beforeEach() { + genesis(); + } + @Test @WithAnonymousUser public void findById_anonymous_succeeds() throws ContainerNotFoundException { diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/DatabaseEndpointUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/DatabaseEndpointUnitTest.java index 02ba52ecaa930f1747ee55f80cff2ea36379ffc1..8ffe328aa95342c6b8ce6fe93a910658ad2ab043 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/DatabaseEndpointUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/DatabaseEndpointUnitTest.java @@ -13,6 +13,7 @@ import at.tuwien.service.ContainerService; import at.tuwien.service.BrokerService; import at.tuwien.service.impl.DatabaseServiceImpl; import lombok.extern.log4j.Log4j2; +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; @@ -62,6 +63,11 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest { @Autowired private DatabaseEndpoint databaseEndpoint; + @BeforeEach + public void beforeEach() { + genesis(); + } + @Test @WithAnonymousUser public void create_anonymous_fails() { @@ -97,7 +103,7 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest { public void create_succeeds() throws DataServiceException, DataServiceConnectionException, UserNotFoundException, DatabaseNotFoundException, ContainerNotFoundException, SearchServiceException, SearchServiceConnectionException, AuthServiceException, AuthServiceConnectionException, - CredentialsInvalidException, BrokerServiceException, BrokerServiceConnectionException { + CredentialsInvalidException, BrokerServiceException, BrokerServiceConnectionException, ContainerQuotaException { final DatabaseCreateDto request = DatabaseCreateDto.builder() .cid(CONTAINER_1_ID) .name(DATABASE_1_NAME) @@ -107,7 +113,7 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest { /* mock */ when(containerService.find(CONTAINER_1_ID)) .thenReturn(CONTAINER_1); - when(databaseService.create(request, USER_1)) + when(databaseService.create(CONTAINER_1, request, USER_1)) .thenReturn(DATABASE_1); doNothing() .when(messageQueueService) @@ -433,7 +439,7 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest { public void create_generic(DatabaseCreateDto data, Principal principal, User user) throws DataServiceException, DataServiceConnectionException, UserNotFoundException, DatabaseNotFoundException, ContainerNotFoundException, SearchServiceException, SearchServiceConnectionException, - BrokerServiceException, BrokerServiceConnectionException { + BrokerServiceException, BrokerServiceConnectionException, ContainerQuotaException { /* mock */ doNothing() diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/ImageEndpointUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/ImageEndpointUnitTest.java index 3d1c37d36348cd90e5239129957506758cc63f1e..c5c3c24cfd37ea0986079132cf67a4e527669892 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/ImageEndpointUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/ImageEndpointUnitTest.java @@ -9,6 +9,7 @@ import at.tuwien.entities.container.image.ContainerImage; import at.tuwien.exception.*; import at.tuwien.service.impl.ImageServiceImpl; import lombok.extern.log4j.Log4j2; +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; @@ -37,6 +38,11 @@ public class ImageEndpointUnitTest extends AbstractUnitTest { @Autowired private ImageEndpoint imageEndpoint; + @BeforeEach + public void beforeEach() { + genesis(); + } + @Test @WithAnonymousUser public void findAll_anonymous_succeeds() { diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/LicenseEndpointUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/LicenseEndpointUnitTest.java index 5be4624021400c25bd130fab4ef150bffb9e328b..f45dd85fb4d13423451599e8ffc3cd046a8ebdca 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/LicenseEndpointUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/LicenseEndpointUnitTest.java @@ -4,6 +4,7 @@ import at.tuwien.test.AbstractUnitTest; import at.tuwien.api.database.LicenseDto; import at.tuwien.repository.LicenseRepository; import lombok.extern.log4j.Log4j2; +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; @@ -30,6 +31,11 @@ public class LicenseEndpointUnitTest extends AbstractUnitTest { @Autowired private LicenseEndpoint licenseEndpoint; + @BeforeEach + public void beforeEach() { + genesis(); + } + @Test public void list_succeeds() { diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/MessageEndpointUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/MessageEndpointUnitTest.java index cea67bc5103de5eeac619f24d0f15c7042d9b115..59166b720076f1541774f6ed8ac3dcc816da9e9a 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/MessageEndpointUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/MessageEndpointUnitTest.java @@ -8,6 +8,7 @@ import at.tuwien.api.maintenance.BannerMessageUpdateDto; import at.tuwien.entities.maintenance.BannerMessage; import at.tuwien.service.BannerMessageService; import lombok.extern.log4j.Log4j2; +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; @@ -35,6 +36,11 @@ public class MessageEndpointUnitTest extends AbstractUnitTest { @Autowired private MessageEndpoint messageEndpoint; + @BeforeEach + public void beforeEach() { + genesis(); + } + @Test @WithAnonymousUser public void list_anonymous_succeeds() { diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/MetadataEndpointUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/MetadataEndpointUnitTest.java index d024978449f6269615839a13067e42c3a02ab784..7ed994534287e13f0f3b33e0c19abcfb360e3f50 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/MetadataEndpointUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/MetadataEndpointUnitTest.java @@ -6,6 +6,7 @@ import at.tuwien.oaipmh.OaiRecordParameters; import at.tuwien.repository.IdentifierRepository; import at.tuwien.utils.XmlUtils; import lombok.extern.log4j.Log4j2; +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; @@ -33,6 +34,11 @@ public class MetadataEndpointUnitTest extends AbstractUnitTest { @Autowired private MetadataEndpoint metadataEndpoint; + @BeforeEach + public void beforeEach() { + genesis(); + } + @Test @WithAnonymousUser public void identify_succeeds() { diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/OntologyEndpointUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/OntologyEndpointUnitTest.java index 297c21a386780d586b9fb1ff23344744a0d312e0..4e19e479353312269ba1c0bd3afd7c983dd6f1ed 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/OntologyEndpointUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/OntologyEndpointUnitTest.java @@ -11,6 +11,7 @@ import lombok.extern.log4j.Log4j2; import org.apache.jena.sys.JenaSystem; import org.hibernate.HibernateException; import org.junit.jupiter.api.BeforeAll; +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; @@ -47,6 +48,11 @@ public class OntologyEndpointUnitTest extends AbstractUnitTest { JenaSystem.init(); } + @BeforeEach + public void beforeEach() { + genesis(); + } + @Test @WithAnonymousUser public void findAll_anonymous_succeeds() { diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/TableEndpointUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/TableEndpointUnitTest.java index 2a9b4ec3825b84ee3682a8294dfa70657bbf4541..1ceb6fd75ff22547f630c85bb7a1cbbb27bd86ab 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/TableEndpointUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/TableEndpointUnitTest.java @@ -1,6 +1,5 @@ package at.tuwien.endpoints; -import at.tuwien.test.AbstractUnitTest; import at.tuwien.api.database.table.TableBriefDto; import at.tuwien.api.database.table.TableCreateDto; import at.tuwien.api.database.table.TableDto; @@ -8,6 +7,9 @@ import at.tuwien.api.database.table.columns.ColumnCreateDto; import at.tuwien.api.database.table.columns.ColumnDto; import at.tuwien.api.database.table.columns.ColumnTypeDto; import at.tuwien.api.database.table.columns.concepts.ColumnSemanticsUpdateDto; +import at.tuwien.api.database.table.constraints.ConstraintsCreateDto; +import at.tuwien.api.semantics.EntityDto; +import at.tuwien.api.semantics.TableColumnEntityDto; import at.tuwien.entities.database.Database; import at.tuwien.entities.database.DatabaseAccess; import at.tuwien.entities.database.table.Table; @@ -15,12 +17,17 @@ import at.tuwien.entities.database.table.columns.TableColumn; import at.tuwien.entities.user.User; import at.tuwien.exception.*; import at.tuwien.service.*; +import at.tuwien.test.AbstractUnitTest; +import at.tuwien.validation.EndpointValidator; import lombok.extern.log4j.Log4j2; import org.apache.jena.sys.JenaSystem; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration; @@ -34,6 +41,7 @@ import org.springframework.test.context.junit.jupiter.SpringExtension; import java.security.Principal; import java.util.List; +import java.util.stream.Stream; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; @@ -57,11 +65,31 @@ public class TableEndpointUnitTest extends AbstractUnitTest { private UserService userService; @MockBean - private BrokerService messageQueueService; + private EntityService entityService; @Autowired private TableEndpoint tableEndpoint; + public static Stream<Arguments> needNothing_parameters() { + return EndpointValidator.NEED_NOTHING.stream() + .map(Arguments::arguments); + } + + public static Stream<Arguments> needSize_parameters() { + return EndpointValidator.NEED_SIZE.stream() + .map(Arguments::arguments); + } + + public static Stream<Arguments> canHaveSize_parameters() { + return EndpointValidator.CAN_HAVE_SIZE.stream() + .map(Arguments::arguments); + } + + public static Stream<Arguments> canHaveSizeAndD_parameters() { + return EndpointValidator.CAN_HAVE_SIZE_AND_D.stream() + .map(Arguments::arguments); + } + @BeforeAll public static void beforeAll() { /* init Apache Jena */ @@ -164,13 +192,15 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_3_USERNAME, authorities = {"create-table"}) - public void create_publicDecimalColumnSizeMissing_fails() { + public void create_publicDecimalColumnSizeTooSmall_fails() { final TableCreateDto request = TableCreateDto.builder() .name("Some Table") .description("Some Description") .columns(List.of(ColumnCreateDto.builder() .name("ID") .type(ColumnTypeDto.DECIMAL) + .size(-1L) // <<< + .d(0L) .build())) .constraints(null) .build(); @@ -183,13 +213,15 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_3_USERNAME, authorities = {"create-table"}) - public void create_publicDateFormatMissing_fails() { + public void create_publicDecimalColumnDTooSmall_fails() { final TableCreateDto request = TableCreateDto.builder() .name("Some Table") .description("Some Description") .columns(List.of(ColumnCreateDto.builder() - .name("timestamp") - .type(ColumnTypeDto.DATE) + .name("ID") + .type(ColumnTypeDto.DECIMAL) + .size(0L) + .d(-1L) // <<< .build())) .constraints(null) .build(); @@ -200,74 +232,125 @@ public class TableEndpointUnitTest extends AbstractUnitTest { }); } - @Test + @ParameterizedTest + @MethodSource("canHaveSize_parameters") @WithMockUser(username = USER_3_USERNAME, authorities = {"create-table"}) - public void create_publicDateTimeFormatMissing_fails() { + public void create_publicOptionalSizeNone_succeeds(ColumnTypeDto columnType) throws UserNotFoundException, SearchServiceException, + NotAllowedException, SemanticEntityNotFoundException, DataServiceConnectionException, TableNotFoundException, MalformedException, DataServiceException, DatabaseNotFoundException, AccessNotFoundException, OntologyNotFoundException, TableExistsException, SearchServiceConnectionException { final TableCreateDto request = TableCreateDto.builder() .name("Some Table") .description("Some Description") .columns(List.of(ColumnCreateDto.builder() - .name("timestamp") - .type(ColumnTypeDto.DATETIME) + .name("ID") + .type(columnType) + .size(null) // <<< + .d(null) // <<< .build())) .constraints(null) .build(); + /* mock */ + when(tableService.createTable(DATABASE_3, request, USER_1_PRINCIPAL)) + .thenReturn(TABLE_1) /* some table */; + /* test */ - assertThrows(MalformedException.class, () -> { + if (EndpointValidator.NEED_SIZE.contains(columnType)) { + assertThrows(MalformedException.class, () -> { + generic_create(DATABASE_3_ID, DATABASE_3, request, USER_1_PRINCIPAL, USER_1, DATABASE_3_USER_1_WRITE_OWN_ACCESS); + }); + } else { generic_create(DATABASE_3_ID, DATABASE_3, request, USER_1_PRINCIPAL, USER_1, DATABASE_3_USER_1_WRITE_OWN_ACCESS); - }); + } } - @Test + @ParameterizedTest + @MethodSource("canHaveSize_parameters") @WithMockUser(username = USER_3_USERNAME, authorities = {"create-table"}) - public void create_publicTimeFormatMissing_fails() { + public void create_publicOptionalSize_succeeds(ColumnTypeDto columnType) throws UserNotFoundException, SearchServiceException, + NotAllowedException, SemanticEntityNotFoundException, DataServiceConnectionException, TableNotFoundException, MalformedException, DataServiceException, DatabaseNotFoundException, AccessNotFoundException, OntologyNotFoundException, TableExistsException, SearchServiceConnectionException { final TableCreateDto request = TableCreateDto.builder() .name("Some Table") .description("Some Description") .columns(List.of(ColumnCreateDto.builder() - .name("timestamp") - .type(ColumnTypeDto.TIME) + .name("ID") + .type(columnType) + .size(40L) + .d(10L) .build())) .constraints(null) .build(); + /* mock */ + when(tableService.createTable(DATABASE_3, request, USER_1_PRINCIPAL)) + .thenReturn(TABLE_1) /* some table */; + /* test */ - assertThrows(MalformedException.class, () -> { - generic_create(DATABASE_3_ID, DATABASE_3, request, USER_1_PRINCIPAL, USER_1, DATABASE_3_USER_1_WRITE_OWN_ACCESS); - }); + generic_create(DATABASE_3_ID, DATABASE_3, request, USER_1_PRINCIPAL, USER_1, DATABASE_3_USER_1_WRITE_OWN_ACCESS); } - @Test + @ParameterizedTest + @MethodSource("needNothing_parameters") + @WithMockUser(username = USER_3_USERNAME, authorities = {"create-table"}) + public void create_publicNeedNothing_succeeds(ColumnTypeDto columnType) throws UserNotFoundException, SearchServiceException, + NotAllowedException, SemanticEntityNotFoundException, DataServiceConnectionException, TableNotFoundException, MalformedException, DataServiceException, DatabaseNotFoundException, AccessNotFoundException, OntologyNotFoundException, TableExistsException, SearchServiceConnectionException { + final TableCreateDto request = TableCreateDto.builder() + .name("Some Table") + .description("Some Description") + .columns(List.of(ColumnCreateDto.builder() + .name("ID") + .type(columnType) + .nullAllowed(false) + .build())) + .constraints(ConstraintsCreateDto.builder() + .uniques(List.of(List.of("ID"))) + .build()) + .build(); + + /* mock */ + when(tableService.createTable(DATABASE_3, request, USER_1_PRINCIPAL)) + .thenReturn(TABLE_1) /* some table */; + + /* test */ + generic_create(DATABASE_3_ID, DATABASE_3, request, USER_1_PRINCIPAL, USER_1, DATABASE_3_USER_1_WRITE_OWN_ACCESS); + } + + @ParameterizedTest + @MethodSource("needSize_parameters") @WithMockUser(username = USER_3_USERNAME, authorities = {"create-table"}) - public void create_publicTimestampFormatMissing_fails() { + public void create_publicNeedSize_succeeds(ColumnTypeDto columnType) throws UserNotFoundException, SearchServiceException, + NotAllowedException, SemanticEntityNotFoundException, DataServiceConnectionException, TableNotFoundException, MalformedException, DataServiceException, DatabaseNotFoundException, AccessNotFoundException, OntologyNotFoundException, TableExistsException, SearchServiceConnectionException { final TableCreateDto request = TableCreateDto.builder() .name("Some Table") .description("Some Description") .columns(List.of(ColumnCreateDto.builder() - .name("timestamp") - .type(ColumnTypeDto.TIMESTAMP) + .name("ID") + .type(columnType) + .size(40L) + .d(10L) .build())) .constraints(null) .build(); + /* mock */ + when(tableService.createTable(DATABASE_3, request, USER_1_PRINCIPAL)) + .thenReturn(TABLE_1) /* some table */; + /* test */ - assertThrows(MalformedException.class, () -> { - generic_create(DATABASE_3_ID, DATABASE_3, request, USER_1_PRINCIPAL, USER_1, DATABASE_3_USER_1_WRITE_OWN_ACCESS); - }); + generic_create(DATABASE_3_ID, DATABASE_3, request, USER_1_PRINCIPAL, USER_1, DATABASE_3_USER_1_WRITE_OWN_ACCESS); } - @Test + @ParameterizedTest + @MethodSource("needSize_parameters") @WithMockUser(username = USER_3_USERNAME, authorities = {"create-table"}) - public void create_publicDecimalColumnSizeTooSmall_fails() { + public void create_publicNeedSizeNone_fails(ColumnTypeDto columnType) { final TableCreateDto request = TableCreateDto.builder() .name("Some Table") .description("Some Description") .columns(List.of(ColumnCreateDto.builder() .name("ID") - .type(ColumnTypeDto.DECIMAL) - .size(-1L) - .d(0L) + .type(columnType) + .size(null) // <<< + .d(10L) .build())) .constraints(null) .build(); @@ -278,16 +361,17 @@ public class TableEndpointUnitTest extends AbstractUnitTest { }); } - @Test + @ParameterizedTest + @MethodSource("canHaveSizeAndD_parameters") @WithMockUser(username = USER_3_USERNAME, authorities = {"create-table"}) - public void create_publicDecimalColumnSizeTooBig_fails() { + public void create_publicCanHaveSizeAndDSizeNone_fails(ColumnTypeDto columnType) { final TableCreateDto request = TableCreateDto.builder() .name("Some Table") .description("Some Description") .columns(List.of(ColumnCreateDto.builder() .name("ID") - .type(ColumnTypeDto.DECIMAL) - .size(66L) + .type(columnType) + .size(null) // <<< .d(0L) .build())) .constraints(null) @@ -299,17 +383,18 @@ public class TableEndpointUnitTest extends AbstractUnitTest { }); } - @Test + @ParameterizedTest + @MethodSource("canHaveSizeAndD_parameters") @WithMockUser(username = USER_3_USERNAME, authorities = {"create-table"}) - public void create_publicDecimalColumnDTooBig_fails() { + public void create_publicCanHaveSizeAndDDNone_fails(ColumnTypeDto columnType) { final TableCreateDto request = TableCreateDto.builder() .name("Some Table") .description("Some Description") .columns(List.of(ColumnCreateDto.builder() .name("ID") - .type(ColumnTypeDto.DECIMAL) + .type(columnType) .size(0L) - .d(39L) + .d(null) // <<< .build())) .constraints(null) .build(); @@ -320,27 +405,112 @@ public class TableEndpointUnitTest extends AbstractUnitTest { }); } - @Test + @ParameterizedTest + @MethodSource("canHaveSizeAndD_parameters") @WithMockUser(username = USER_3_USERNAME, authorities = {"create-table"}) - public void create_publicDecimalColumnDBiggerSize_fails() { + public void create_publicCanHaveSizeAndDBothNone_succeeds(ColumnTypeDto columnType) throws UserNotFoundException, + SearchServiceException, NotAllowedException, SemanticEntityNotFoundException, + DataServiceConnectionException, TableNotFoundException, MalformedException, DataServiceException, + DatabaseNotFoundException, AccessNotFoundException, OntologyNotFoundException, TableExistsException, + SearchServiceConnectionException { final TableCreateDto request = TableCreateDto.builder() .name("Some Table") .description("Some Description") .columns(List.of(ColumnCreateDto.builder() .name("ID") - .type(ColumnTypeDto.DECIMAL) - .size(9L) - .d(10L) + .type(columnType) + .size(null) // <<< + .d(null) // <<< .build())) .constraints(null) .build(); + /* mock */ + when(tableService.createTable(DATABASE_3, request, USER_1_PRINCIPAL)) + .thenReturn(TABLE_1) /* some table */; + + /* test */ + generic_create(DATABASE_3_ID, DATABASE_3, request, USER_1_PRINCIPAL, USER_1, DATABASE_3_USER_1_WRITE_OWN_ACCESS); + } + + @Test + @WithMockUser(username = USER_3_USERNAME, authorities = {"create-table"}) + public void create_publicHasMultipleSerial_fails() { + final TableCreateDto request = TableCreateDto.builder() + .name("Some Table") + .description("Some Description") + .columns(List.of(ColumnCreateDto.builder() + .name("ID") + .type(ColumnTypeDto.SERIAL) + .nullAllowed(false) + .build(), + ColumnCreateDto.builder() + .name("Counter") + .type(ColumnTypeDto.SERIAL) + .nullAllowed(false) + .build())) + .constraints(ConstraintsCreateDto.builder() + .uniques(List.of(List.of("ID"), + List.of("Counter"))) + .build()) + .build(); + /* test */ assertThrows(MalformedException.class, () -> { generic_create(DATABASE_3_ID, DATABASE_3, request, USER_1_PRINCIPAL, USER_1, DATABASE_3_USER_1_WRITE_OWN_ACCESS); }); } + @Test + @WithMockUser(username = USER_3_USERNAME, authorities = {"create-table"}) + public void create_publicSerialNullAllowed_fails() { + final TableCreateDto request = TableCreateDto.builder() + .name("Some Table") + .description("Some Description") + .columns(List.of(ColumnCreateDto.builder() + .name("ID") + .type(ColumnTypeDto.SERIAL) + .nullAllowed(true) // <<< + .build())) + .constraints(ConstraintsCreateDto.builder() + .uniques(List.of(List.of("ID"))) + .build()) + .build(); + + /* test */ + assertThrows(MalformedException.class, () -> { + generic_create(DATABASE_3_ID, DATABASE_3, request, USER_1_PRINCIPAL, USER_1, DATABASE_3_USER_1_WRITE_OWN_ACCESS); + }); + } + + @ParameterizedTest + @MethodSource("canHaveSizeAndD_parameters") + @WithMockUser(username = USER_3_USERNAME, authorities = {"create-table"}) + public void create_publicCanHaveSizeAndDBothNotNone_succeeds(ColumnTypeDto columnType) throws UserNotFoundException, + SearchServiceException, NotAllowedException, SemanticEntityNotFoundException, + DataServiceConnectionException, TableNotFoundException, MalformedException, DataServiceException, + DatabaseNotFoundException, AccessNotFoundException, OntologyNotFoundException, TableExistsException, + SearchServiceConnectionException { + final TableCreateDto request = TableCreateDto.builder() + .name("Some Table") + .description("Some Description") + .columns(List.of(ColumnCreateDto.builder() + .name("ID") + .type(columnType) + .size(0L) // <<< + .d(0L) // <<< + .build())) + .constraints(null) + .build(); + + /* mock */ + when(tableService.createTable(DATABASE_3, request, USER_1_PRINCIPAL)) + .thenReturn(TABLE_1) /* some table */; + + /* test */ + generic_create(DATABASE_3_ID, DATABASE_3, request, USER_1_PRINCIPAL, USER_1, DATABASE_3_USER_1_WRITE_OWN_ACCESS); + } + @Test @WithAnonymousUser public void findById_publicAnonymous_succeeds() throws DataServiceException, DataServiceConnectionException, @@ -390,6 +560,64 @@ public class TableEndpointUnitTest extends AbstractUnitTest { generic_findById(DATABASE_3_ID, DATABASE_3, TABLE_8_ID, TABLE_8, USER_1_PRINCIPAL, USER_1, null); } + @Test + @WithAnonymousUser + public void analyseTable_anonymous_fails() { + + /* test */ + assertThrows(org.springframework.security.access.AccessDeniedException.class, () -> { + analyseTable_generic(DATABASE_1_ID, TABLE_1_ID, TABLE_1); + }); + } + + @Test + @WithMockUser(username = USER_4_USERNAME) + public void findAll_noRole_fails() { + + /* test */ + assertThrows(org.springframework.security.access.AccessDeniedException.class, () -> { + analyseTable_generic(DATABASE_1_ID, TABLE_1_ID, TABLE_1); + }); + } + + @Test + @WithMockUser(username = USER_1_USERNAME, authorities = {"table-semantic-analyse"}) + public void findAll_hasRole_succeeds() throws MalformedException, TableNotFoundException, + DatabaseNotFoundException { + + /* test */ + analyseTable_generic(DATABASE_1_ID, TABLE_1_ID, TABLE_1); + } + + @Test + @WithAnonymousUser + public void analyseTableColumn_anonymous_fails() { + + /* test */ + assertThrows(org.springframework.security.access.AccessDeniedException.class, () -> { + analyseTableColumn_generic(DATABASE_1_ID, TABLE_1_ID, TABLE_1_COLUMNS.get(0).getId(), TABLE_1_COLUMNS.get(0)); + }); + } + + @Test + @WithMockUser(username = USER_4_USERNAME) + public void analyseTableColumn_noRole_fails() { + + /* test */ + assertThrows(org.springframework.security.access.AccessDeniedException.class, () -> { + analyseTableColumn_generic(DATABASE_1_ID, TABLE_1_ID, TABLE_1_COLUMNS.get(0).getId(), TABLE_1_COLUMNS.get(0)); + }); + } + + @Test + @WithMockUser(username = USER_1_USERNAME, authorities = {"table-semantic-analyse"}) + public void analyseTableColumn_hasRole_succeeds() throws MalformedException, TableNotFoundException, + DatabaseNotFoundException { + + /* test */ + analyseTableColumn_generic(DATABASE_1_ID, TABLE_1_ID, TABLE_1_COLUMNS.get(0).getId(), TABLE_1_COLUMNS.get(0)); + } + @Test @WithAnonymousUser public void update_publicAnonymous_fails() { @@ -774,6 +1002,34 @@ public class TableEndpointUnitTest extends AbstractUnitTest { /* ## GENERIC TEST CASES ## */ /* ################################################################################################### */ + public void analyseTable_generic(Long databaseId, Long tableId, Table table) throws MalformedException, + TableNotFoundException, DatabaseNotFoundException { + + /* mock */ + when(entityService.suggestByTable(table)) + .thenReturn(List.of()); + + /* test */ + final ResponseEntity<List<EntityDto>> response = tableEndpoint.analyseTable(databaseId, tableId); + assertEquals(HttpStatus.OK, response.getStatusCode()); + final List<EntityDto> body = response.getBody(); + assertNotNull(body); + } + + public void analyseTableColumn_generic(Long databaseId, Long tableId, Long columnId, TableColumn tableColumn) + throws MalformedException, TableNotFoundException, DatabaseNotFoundException { + + /* mock */ + when(entityService.suggestByColumn(tableColumn)) + .thenReturn(List.of()); + + /* test */ + final ResponseEntity<List<TableColumnEntityDto>> response = tableEndpoint.analyseTableColumn(databaseId, tableId, columnId); + assertEquals(HttpStatus.OK, response.getStatusCode()); + final List<TableColumnEntityDto> body = response.getBody(); + assertNotNull(body); + } + protected ResponseEntity<List<TableBriefDto>> generic_list(Long databaseId, Database database, Principal principal, User user, DatabaseAccess access) throws NotAllowedException, DatabaseNotFoundException, AccessNotFoundException, UserNotFoundException { diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/UnitEndpointUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/UnitEndpointUnitTest.java index b5fc19681ccb34f41fce526c12a0de7238a1bfa7..7d74e615be3a24dfd16af29c825774361f1a7ffc 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/UnitEndpointUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/UnitEndpointUnitTest.java @@ -4,6 +4,7 @@ import at.tuwien.test.AbstractUnitTest; import at.tuwien.api.database.table.columns.concepts.UnitDto; import at.tuwien.service.UnitService; import lombok.extern.log4j.Log4j2; +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; @@ -31,6 +32,11 @@ public class UnitEndpointUnitTest extends AbstractUnitTest { @Autowired private UnitEndpoint unitEndpoint; + @BeforeEach + public void beforeEach() { + genesis(); + } + @Test @WithAnonymousUser public void findAllUnits_anonymous_succeeds() { diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/UserEndpointUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/UserEndpointUnitTest.java index f5e413e0e9de10192bca89d4fe823db02924712d..da86dd9344606e59c55a9037111877fc55fcb1c4 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/UserEndpointUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/UserEndpointUnitTest.java @@ -8,6 +8,7 @@ import at.tuwien.exception.*; import at.tuwien.service.AuthenticationService; import at.tuwien.service.UserService; import lombok.extern.log4j.Log4j2; +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; @@ -43,20 +44,44 @@ public class UserEndpointUnitTest extends AbstractUnitTest { @Autowired private UserEndpoint userEndpoint; + @BeforeEach + public void beforeEach() { + genesis(); + } + @Test @WithAnonymousUser - public void findAll_anonymous_succeeds() { + public void findAll_anonymous_succeeds() throws UserNotFoundException { /* test */ - findAll_generic(); + final List<UserBriefDto> response = findAll_generic(null, null); + assertEquals(2, response.size()); } @Test @WithMockUser(username = USER_1_USERNAME) - public void findAll_noRole_succeeds() { + public void findAll_noRole_succeeds() throws UserNotFoundException { + + /* test */ + final List<UserBriefDto> response = findAll_generic(null, null); + assertEquals(2, response.size()); + } + + @Test + public void findAll_filterUsername_succeeds() throws UserNotFoundException { /* test */ - findAll_generic(); + final List<UserBriefDto> response = findAll_generic(USER_2_USERNAME, USER_2); + assertEquals(1, response.size()); + assertEquals(USER_2_ID, response.get(0).getId()); + } + + @Test + public void findAll_filterUsername_fails() throws UserNotFoundException { + + /* test */ + final List<UserBriefDto> response = findAll_generic(USER_5_USERNAME, null); + assertEquals(0, response.size()); } @Test @@ -100,7 +125,7 @@ public class UserEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_1_USERNAME) - public void find_self_succeeds() throws NotAllowedException, UserNotFoundException{ + public void find_self_succeeds() throws NotAllowedException, UserNotFoundException { /* test */ find_generic(USER_1_ID, USER_1, USER_1_PRINCIPAL); @@ -231,18 +256,29 @@ public class UserEndpointUnitTest extends AbstractUnitTest { /* ## GENERIC TEST CASES ## */ /* ################################################################################################### */ - protected void findAll_generic() { + protected List<UserBriefDto> findAll_generic(String username, User user) throws UserNotFoundException { /* mock */ - when(userService.findAll()) - .thenReturn(List.of(USER_1, USER_2)); + if (username != null) { + if (user != null) { + when(userService.findByUsername(username)) + .thenReturn(user); + } else { + doThrow(UserNotFoundException.class) + .when(userService) + .findByUsername(username); + } + } else { + when(userService.findAll()) + .thenReturn(List.of(USER_1, USER_2)); + } /* test */ - final ResponseEntity<List<UserBriefDto>> response = userEndpoint.findAll(); + final ResponseEntity<List<UserBriefDto>> response = userEndpoint.findAll(username); assertEquals(HttpStatus.OK, response.getStatusCode()); final List<UserBriefDto> body = response.getBody(); assertNotNull(body); - assertEquals(2, body.size()); + return response.getBody(); } protected void create_generic(SignupRequestDto data, User user, at.tuwien.api.keycloak.UserDto userDto, UUID id) @@ -265,7 +301,7 @@ public class UserEndpointUnitTest extends AbstractUnitTest { } protected void find_generic(UUID id, User user, Principal principal) throws NotAllowedException, - UserNotFoundException{ + UserNotFoundException { /* mock */ if (user != null) { diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/ViewEndpointUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/ViewEndpointUnitTest.java index 74e418f42b1ca4fc4cbceec451f645ec05c1223d..b4291ce902652eeeea7aa7e12f6aac26d444bbe1 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/ViewEndpointUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/ViewEndpointUnitTest.java @@ -14,6 +14,7 @@ import at.tuwien.service.DatabaseService; import at.tuwien.service.UserService; import at.tuwien.service.ViewService; import lombok.extern.log4j.Log4j2; +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; @@ -52,6 +53,11 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { @Autowired private ViewEndpoint viewEndpoint; + @BeforeEach + public void beforeEach() { + genesis(); + } + @Test @WithAnonymousUser public void findAll_publicAnonymous_succeeds() throws ViewNotFoundException, UserNotFoundException, diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/BrokerServiceGatewayUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/BrokerServiceGatewayUnitTest.java index a812bd5de49af37c5eca041a2fb36653d243dafc..fc2a9c2c220c4fa601138ee9ee8333d3cd67f493 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/BrokerServiceGatewayUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/BrokerServiceGatewayUnitTest.java @@ -1,5 +1,6 @@ package at.tuwien.gateway; +import at.tuwien.api.amqp.GrantExchangePermissionsDto; import at.tuwien.test.AbstractUnitTest; import at.tuwien.exception.*; import lombok.extern.log4j.Log4j2; @@ -33,6 +34,12 @@ public class BrokerServiceGatewayUnitTest extends AbstractUnitTest { @Autowired private BrokerServiceGateway brokerServiceGateway; + private final GrantExchangePermissionsDto WRITE_ALL_PERMISSIONS = GrantExchangePermissionsDto.builder() + .exchange("dbrepo") + .read("^(dbrepo\\.1\\..*)$") /* WRITE_ALL */ + .write("^(dbrepo\\.1\\..*)$") + .build(); + @Test public void grantTopicPermission_exchangeNoRightsBefore_succeeds() throws BrokerServiceException, BrokerServiceConnectionException { @@ -178,43 +185,40 @@ public class BrokerServiceGatewayUnitTest extends AbstractUnitTest { @Test public void grantExchangePermission_succeeds() throws BrokerServiceException, BrokerServiceConnectionException { - final ResponseEntity<Void> mock = ResponseEntity.status(HttpStatus.CREATED) - .build(); /* mock */ when(restTemplate.exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(Void.class))) - .thenReturn(mock); + .thenReturn(ResponseEntity.status(HttpStatus.CREATED) + .build()); /* test */ - brokerServiceGateway.grantExchangePermission(USER_1_USERNAME, USER_1_RABBITMQ_GRANT_TOPIC_DTO); + brokerServiceGateway.grantExchangePermission(USER_1_USERNAME, WRITE_ALL_PERMISSIONS); } @Test public void grantExchangePermission_exists_succeeds() throws BrokerServiceException, BrokerServiceConnectionException { - final ResponseEntity<Void> mock = ResponseEntity.status(HttpStatus.NO_CONTENT) - .build(); /* mock */ when(restTemplate.exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(Void.class))) - .thenReturn(mock); + .thenReturn(ResponseEntity.status(HttpStatus.NO_CONTENT) + .build()); /* test */ - brokerServiceGateway.grantExchangePermission(USER_1_USERNAME, USER_1_RABBITMQ_GRANT_TOPIC_DTO); + brokerServiceGateway.grantExchangePermission(USER_1_USERNAME, WRITE_ALL_PERMISSIONS); } @Test public void grantExchangePermission_unexpected2_fails() { - final ResponseEntity<Void> mock = ResponseEntity.status(HttpStatus.BAD_GATEWAY) - .build(); /* mock */ when(restTemplate.exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(Void.class))) - .thenReturn(mock); + .thenReturn(ResponseEntity.status(HttpStatus.BAD_GATEWAY) + .build()); /* test */ assertThrows(BrokerServiceException.class, () -> { - brokerServiceGateway.grantExchangePermission(USER_1_USERNAME, USER_1_RABBITMQ_GRANT_TOPIC_DTO); + brokerServiceGateway.grantExchangePermission(USER_1_USERNAME, WRITE_ALL_PERMISSIONS); }); } @@ -228,7 +232,7 @@ public class BrokerServiceGatewayUnitTest extends AbstractUnitTest { /* test */ assertThrows(BrokerServiceConnectionException.class, () -> { - brokerServiceGateway.grantExchangePermission(USER_1_USERNAME, USER_1_RABBITMQ_GRANT_TOPIC_DTO); + brokerServiceGateway.grantExchangePermission(USER_1_USERNAME, WRITE_ALL_PERMISSIONS); }); } @@ -242,7 +246,7 @@ public class BrokerServiceGatewayUnitTest extends AbstractUnitTest { /* test */ assertThrows(BrokerServiceException.class, () -> { - brokerServiceGateway.grantExchangePermission(USER_1_USERNAME, USER_1_RABBITMQ_GRANT_TOPIC_DTO); + brokerServiceGateway.grantExchangePermission(USER_1_USERNAME, WRITE_ALL_PERMISSIONS); }); } diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/DataServiceGatewayUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/DataServiceGatewayUnitTest.java index 8183ea90808ea6c7e48e1530ea2a88a62a34df9b..698f7ed524c13bbb3d9fbe5fca37003419f51a4c 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/DataServiceGatewayUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/DataServiceGatewayUnitTest.java @@ -1103,7 +1103,7 @@ public class DataServiceGatewayUnitTest extends AbstractUnitTest { } @Test - public void getTableStatistics_emptyBody_fails() { + public void getTableStatistics_emptyBody_fails() throws TableNotFoundException, DataServiceException, DataServiceConnectionException { /* mock */ when(dataServiceRestTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(TableStatisticDto.class))) @@ -1111,9 +1111,7 @@ public class DataServiceGatewayUnitTest extends AbstractUnitTest { .build()); /* test */ - assertThrows(DataServiceException.class, () -> { - dataServiceGateway.getTableStatistics(DATABASE_3_ID, TABLE_8_ID); - }); + dataServiceGateway.getTableStatistics(DATABASE_3_ID, TABLE_8_ID); } } diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/MetadataMapperUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/MetadataMapperUnitTest.java index 8a72f2cabbe0f4eda33ff77ef125eed2c842e12d..c84990098596b159be2aa65459638ba0b498c7ee 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/MetadataMapperUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/MetadataMapperUnitTest.java @@ -182,8 +182,6 @@ public class MetadataMapperUnitTest extends AbstractUnitTest { @Test public void customDatabaseToDatabaseDto_succeeds() { - final Database debug = DATABASE_1; - /* test */ final DatabaseDto response = metadataMapper.customDatabaseToDatabaseDto(DATABASE_1); assertEquals(DATABASE_1_ID, response.getId()); @@ -241,11 +239,10 @@ public class MetadataMapperUnitTest extends AbstractUnitTest { assertEquals(TABLE_1_COLUMNS.get(i).getTable().getId(), table0.getColumns().get(i).getTableId()); assertEquals(TABLE_1_COLUMNS.get(i).getName(), table0.getColumns().get(i).getName()); assertEquals(TABLE_1_COLUMNS.get(i).getInternalName(), table0.getColumns().get(i).getInternalName()); - assertEquals(List.of(ColumnTypeDto.BIGINT, ColumnTypeDto.DATE, ColumnTypeDto.VARCHAR, ColumnTypeDto.DECIMAL, ColumnTypeDto.DECIMAL).get(i), table0.getColumns().get(i).getColumnType()); + assertEquals(List.of(ColumnTypeDto.SERIAL, ColumnTypeDto.DATE, ColumnTypeDto.VARCHAR, ColumnTypeDto.DECIMAL, ColumnTypeDto.DECIMAL).get(i), table0.getColumns().get(i).getColumnType()); assertEquals(TABLE_1_COLUMNS.get(i).getSize(), table0.getColumns().get(i).getSize()); assertEquals(TABLE_1_COLUMNS.get(i).getD(), table0.getColumns().get(i).getD()); assertEquals(TABLE_1_COLUMNS.get(i).getIsNullAllowed(), table0.getColumns().get(i).getIsNullAllowed()); - assertEquals(TABLE_1_COLUMNS.get(i).getAutoGenerated(), table0.getColumns().get(i).getAutoGenerated()); assertEquals(TABLE_1_COLUMNS.get(i).getEnums(), table0.getColumns().get(i).getEnums()); assertEquals(TABLE_1_COLUMNS.get(i).getSets(), table0.getColumns().get(i).getSets()); } @@ -264,7 +261,7 @@ public class MetadataMapperUnitTest extends AbstractUnitTest { assertEquals(TABLE_1_COLUMNS_BRIEF_0_DTO.getInternalName(), table0pk.getColumn().getInternalName()); assertEquals(TABLE_1_ID, table0pk.getTable().getId()); assertEquals(DATABASE_1_ID, table0pk.getTable().getDatabaseId()); - assertEquals(ColumnTypeDto.BIGINT, table0pk.getColumn().getColumnType()); + assertEquals(ColumnTypeDto.SERIAL, table0pk.getColumn().getColumnType()); assertNull(table0pk.getColumn().getAlias()); assertEquals(TABLE_1_ID, table0pk.getColumn().getTableId()); assertEquals(DATABASE_1_ID, table0pk.getColumn().getDatabaseId()); @@ -298,7 +295,6 @@ public class MetadataMapperUnitTest extends AbstractUnitTest { assertEquals(TABLE_2_COLUMNS.get(i).getSize(), table1.getColumns().get(i).getSize()); assertEquals(TABLE_2_COLUMNS.get(i).getD(), table1.getColumns().get(i).getD()); assertEquals(TABLE_2_COLUMNS.get(i).getIsNullAllowed(), table1.getColumns().get(i).getIsNullAllowed()); - assertEquals(TABLE_2_COLUMNS.get(i).getAutoGenerated(), table1.getColumns().get(i).getAutoGenerated()); assertEquals(TABLE_2_COLUMNS.get(i).getEnums(), table1.getColumns().get(i).getEnums()); assertEquals(TABLE_2_COLUMNS.get(i).getSets(), table1.getColumns().get(i).getSets()); } @@ -372,7 +368,6 @@ public class MetadataMapperUnitTest extends AbstractUnitTest { assertEquals(TABLE_3_COLUMNS.get(i).getSize(), table2.getColumns().get(i).getSize()); assertEquals(TABLE_3_COLUMNS.get(i).getD(), table2.getColumns().get(i).getD()); assertEquals(TABLE_3_COLUMNS.get(i).getIsNullAllowed(), table2.getColumns().get(i).getIsNullAllowed()); - assertEquals(TABLE_3_COLUMNS.get(i).getAutoGenerated(), table2.getColumns().get(i).getAutoGenerated()); assertEquals(TABLE_3_COLUMNS.get(i).getEnums(), table2.getColumns().get(i).getEnums()); assertEquals(TABLE_3_COLUMNS.get(i).getSets(), table2.getColumns().get(i).getSets()); } @@ -417,7 +412,6 @@ public class MetadataMapperUnitTest extends AbstractUnitTest { assertEquals(TABLE_4_COLUMNS.get(i).getSize(), table3.getColumns().get(i).getSize()); assertEquals(TABLE_4_COLUMNS.get(i).getD(), table3.getColumns().get(i).getD()); assertEquals(TABLE_4_COLUMNS.get(i).getIsNullAllowed(), table3.getColumns().get(i).getIsNullAllowed()); - assertEquals(TABLE_4_COLUMNS.get(i).getAutoGenerated(), table3.getColumns().get(i).getAutoGenerated()); assertEquals(TABLE_4_COLUMNS.get(i).getEnums(), table3.getColumns().get(i).getEnums()); assertEquals(TABLE_4_COLUMNS.get(i).getSets(), table3.getColumns().get(i).getSets()); } diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mvc/AuthenticationPrivilegedIntegrationMvcTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mvc/AuthenticationPrivilegedIntegrationMvcTest.java index 5b2e607ec1ba9c6fe33055d4533042da4e88b2f9..474db3910bef5233d676bf387edd63afcd4aa5c6 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mvc/AuthenticationPrivilegedIntegrationMvcTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mvc/AuthenticationPrivilegedIntegrationMvcTest.java @@ -81,8 +81,8 @@ public class AuthenticationPrivilegedIntegrationMvcTest extends AbstractUnitTest genesis(); /* metadata database */ licenseRepository.save(LICENSE_1); - containerRepository.save(CONTAINER_1); userRepository.saveAll(List.of(USER_1, USER_2, USER_3, USER_4)); + containerRepository.save(CONTAINER_1); databaseRepository.save(DATABASE_1); /* keycloak */ keycloakUtils.deleteUser(USER_1_USERNAME); diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mvc/PrometheusEndpointMvcTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mvc/PrometheusEndpointMvcTest.java index ce621be569b0ec20b934ca284508e1b45e76b188..a4f72b977d51e5b9042c9ab1530bf344de184cb8 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mvc/PrometheusEndpointMvcTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mvc/PrometheusEndpointMvcTest.java @@ -551,7 +551,7 @@ public class PrometheusEndpointMvcTest extends AbstractUnitTest { /* mock */ try { - userEndpoint.findAll(); + userEndpoint.findAll(null); } catch (Exception e) { /* ignore */ } diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/AuthenticationServiceIntegrationTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/AuthenticationServiceIntegrationTest.java index 4125529155b135dae929fa7192db073e20dc9f55..fa1cd5d4beeb1fe8fb40d8f59fa974b5d2501dba 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/AuthenticationServiceIntegrationTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/AuthenticationServiceIntegrationTest.java @@ -6,6 +6,7 @@ import at.tuwien.exception.*; import at.tuwien.gateway.KeycloakGateway; import dasniko.testcontainers.keycloak.KeycloakContainer; import lombok.extern.log4j.Log4j2; +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; @@ -31,6 +32,11 @@ public class AuthenticationServiceIntegrationTest extends AbstractUnitTest { @Autowired private KeycloakGateway keycloakGateway; + @BeforeEach + public void beforeEach() { + genesis(); + } + @Container private static KeycloakContainer keycloakContainer = new KeycloakContainer("quay.io/keycloak/keycloak:24.0") .withImagePullPolicy(PullPolicy.alwaysPull()) diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/BrokerServiceIntegrationTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/BrokerServiceIntegrationTest.java index c9a2ad62b61d324934236c885bf6be2aca586e9e..d04409c87b095cfcdc41a478df87a733cdf1bb82 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/BrokerServiceIntegrationTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/BrokerServiceIntegrationTest.java @@ -1,13 +1,15 @@ package at.tuwien.service; -import at.tuwien.config.RabbitConfig; -import at.tuwien.exception.*; -import at.tuwien.test.AbstractUnitTest; import at.tuwien.api.amqp.GrantExchangePermissionsDto; +import at.tuwien.api.amqp.GrantVirtualHostPermissionsDto; import at.tuwien.api.amqp.TopicPermissionDto; import at.tuwien.api.amqp.VirtualHostPermissionDto; +import at.tuwien.config.RabbitConfig; import at.tuwien.entities.database.DatabaseAccess; import at.tuwien.entities.user.User; +import at.tuwien.exception.BrokerServiceConnectionException; +import at.tuwien.exception.BrokerServiceException; +import at.tuwien.test.AbstractUnitTest; import at.tuwien.utils.AmqpUtils; import lombok.extern.log4j.Log4j2; import org.junit.jupiter.api.BeforeEach; @@ -27,7 +29,7 @@ import org.testcontainers.junit.jupiter.Testcontainers; import java.util.List; import java.util.Set; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; @Log4j2 @Testcontainers @@ -167,10 +169,15 @@ public class BrokerServiceIntegrationTest extends AbstractUnitTest { protected VirtualHostPermissionDto setVirtualHostPermissions_generic() throws BrokerServiceException, BrokerServiceConnectionException { + final GrantVirtualHostPermissionsDto permissions = GrantVirtualHostPermissionsDto.builder() + .configure("") + .read("") + .write("") + .build(); final AmqpUtils amqpUtils = new AmqpUtils(rabbitContainer.getHttpUrl()); /* mock */ - amqpUtils.setVirtualHostPermissions(REALM_DBREPO_NAME, USER_1_USERNAME, USER_1_RABBITMQ_GRANT_DTO); + amqpUtils.setVirtualHostPermissions(REALM_DBREPO_NAME, USER_1_USERNAME, permissions); /* test */ brokerService.setVirtualHostPermissions(USER_1); diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/DataCiteIdentifierServicePersistenceTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/DataCiteIdentifierServicePersistenceTest.java index 0c0cf075c4d83645a7df6bae035cbae4d458ad1e..648bb6ab290b319a817aba31d49310d43416e4a3 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/DataCiteIdentifierServicePersistenceTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/DataCiteIdentifierServicePersistenceTest.java @@ -76,8 +76,8 @@ public class DataCiteIdentifierServicePersistenceTest extends AbstractUnitTest { genesis(); /* metadata database */ licenseRepository.save(LICENSE_1); - containerRepository.saveAll(List.of(CONTAINER_1, CONTAINER_2, CONTAINER_3, CONTAINER_4)); userRepository.saveAll(List.of(USER_1, USER_2, USER_3, USER_4, USER_5)); + containerRepository.saveAll(List.of(CONTAINER_1, CONTAINER_2, CONTAINER_3, CONTAINER_4)); databaseRepository.saveAll(List.of(DATABASE_1, DATABASE_2, DATABASE_3, DATABASE_4)); } diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/DatabaseServicePersistenceTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/DatabaseServicePersistenceTest.java index 283450cc256197b1add589295304bd69fbe89dab..51b6df4d27b7af3332e5cb592c627e1e2ae03995 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/DatabaseServicePersistenceTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/DatabaseServicePersistenceTest.java @@ -47,8 +47,8 @@ public class DatabaseServicePersistenceTest extends AbstractUnitTest { genesis(); /* metadata database */ licenseRepository.save(LICENSE_1); - containerRepository.saveAll(List.of(CONTAINER_1, CONTAINER_2, CONTAINER_3, CONTAINER_4)); userRepository.saveAll(List.of(USER_1, USER_2, USER_3, USER_4, USER_5)); + containerRepository.saveAll(List.of(CONTAINER_1, CONTAINER_2, CONTAINER_3, CONTAINER_4)); databaseRepository.saveAll(List.of(DATABASE_1, DATABASE_2, DATABASE_3, DATABASE_4)); } @@ -82,8 +82,6 @@ public class DatabaseServicePersistenceTest extends AbstractUnitTest { assertEquals(IMAGE_1_DRIVER, response.getContainer().getImage().getDriverClass()); assertEquals(IMAGE_1_REGISTRY, response.getContainer().getImage().getRegistry()); assertEquals(IMAGE_1_PORT, response.getContainer().getImage().getDefaultPort()); - assertNotNull(response.getContainer().getImage().getDateFormats()); - assertEquals(4, response.getContainer().getImage().getDateFormats().size()); /* creator */ assertNotNull(response.getCreator()); assertEquals(USER_1_ID, response.getCreator().getId()); @@ -124,8 +122,6 @@ public class DatabaseServicePersistenceTest extends AbstractUnitTest { assertEquals(IMAGE_1_DRIVER, response.getContainer().getImage().getDriverClass()); assertEquals(IMAGE_1_REGISTRY, response.getContainer().getImage().getRegistry()); assertEquals(IMAGE_1_PORT, response.getContainer().getImage().getDefaultPort()); - assertNotNull(response.getContainer().getImage().getDateFormats()); - assertEquals(4, response.getContainer().getImage().getDateFormats().size()); /* creator */ assertNotNull(response.getCreator()); assertEquals(USER_1_ID, response.getCreator().getId()); diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/DatabaseServiceUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/DatabaseServiceUnitTest.java index ea58ae16e4ac35931bb5f713b197bacdc37b6958..1e7633b851f9c052fd8fe60d14193698565421f3 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/DatabaseServiceUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/DatabaseServiceUnitTest.java @@ -1,7 +1,5 @@ package at.tuwien.service; -import at.tuwien.test.AbstractUnitTest; -import at.tuwien.api.database.DatabaseCreateDto; import at.tuwien.api.database.DatabaseModifyVisibilityDto; import at.tuwien.api.database.internal.CreateDatabaseDto; import at.tuwien.entities.database.Database; @@ -9,8 +7,8 @@ import at.tuwien.entities.user.User; import at.tuwien.exception.*; import at.tuwien.gateway.DataServiceGateway; import at.tuwien.gateway.SearchServiceGateway; -import at.tuwien.repository.ContainerRepository; import at.tuwien.repository.DatabaseRepository; +import at.tuwien.test.AbstractUnitTest; import lombok.extern.log4j.Log4j2; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -24,10 +22,10 @@ import java.util.List; import java.util.Optional; import static org.junit.jupiter.api.Assertions.*; -import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.when; @Log4j2 @SpringBootTest @@ -43,9 +41,6 @@ public class DatabaseServiceUnitTest extends AbstractUnitTest { @MockBean private DatabaseRepository databaseRepository; - @MockBean - private ContainerRepository containerRepository; - @Autowired private DatabaseService databaseService; @@ -92,23 +87,6 @@ public class DatabaseServiceUnitTest extends AbstractUnitTest { }); } - @Test - public void create_notFound_fails() { - final DatabaseCreateDto request = DatabaseCreateDto.builder() - .cid(CONTAINER_1_ID) - .name(DATABASE_1_NAME) - .build(); - - /* mock */ - when(containerRepository.findById(CONTAINER_1_ID)) - .thenReturn(Optional.empty()); - - /* test */ - assertThrows(ContainerNotFoundException.class, () -> { - databaseService.create(request, USER_1); - }); - } - @Test public void find_succeeds() throws DatabaseNotFoundException { @@ -138,26 +116,11 @@ public class DatabaseServiceUnitTest extends AbstractUnitTest { public void create_succeeds() throws Exception { /* mock */ - when(containerRepository.findById(DATABASE_1.getCid())) - .thenReturn(Optional.of(CONTAINER_1)); when(dataServiceGateway.createDatabase(any(CreateDatabaseDto.class))) .thenReturn(DATABASE_1_DTO); /* test */ - generic_create(DATABASE_1_CREATE, DATABASE_1); - } - - @Test - public void create_containerNotFound_fails() { - - /* mock */ - when(containerRepository.findById(anyLong())) - .thenReturn(Optional.empty()); - - /* test */ - assertThrows(ContainerNotFoundException.class, () -> { - generic_create(DATABASE_1_CREATE, DATABASE_1); - }); + generic_create(); } @Test @@ -165,15 +128,13 @@ public class DatabaseServiceUnitTest extends AbstractUnitTest { DatabaseNotFoundException { /* mock */ - when(containerRepository.findById(DATABASE_1.getCid())) - .thenReturn(Optional.of(CONTAINER_1)); doThrow(DataServiceException.class) .when(dataServiceGateway) .createDatabase(any(CreateDatabaseDto.class)); /* test */ assertThrows(DataServiceException.class, () -> { - generic_create(DATABASE_1_CREATE, DATABASE_1); + generic_create(); }); } @@ -182,15 +143,13 @@ public class DatabaseServiceUnitTest extends AbstractUnitTest { DatabaseNotFoundException { /* mock */ - when(containerRepository.findById(DATABASE_1.getCid())) - .thenReturn(Optional.of(CONTAINER_1)); doThrow(DataServiceConnectionException.class) .when(dataServiceGateway) .createDatabase(any(CreateDatabaseDto.class)); /* test */ assertThrows(DataServiceConnectionException.class, () -> { - generic_create(DATABASE_1_CREATE, DATABASE_1); + generic_create(); }); } @@ -252,7 +211,11 @@ public class DatabaseServiceUnitTest extends AbstractUnitTest { SearchServiceConnectionException { /* test */ - generic_modifyOwner(DATABASE_1, USER_1); + final Database response = generic_modifyOwner(DATABASE_1, USER_2); + assertEquals(USER_2, response.getOwner()); + assertEquals(USER_2_ID, response.getOwnedBy()); + assertEquals(USER_2, response.getContact()); + assertEquals(USER_2_ID, response.getContactPerson()); } @Test @@ -304,7 +267,7 @@ public class DatabaseServiceUnitTest extends AbstractUnitTest { /* ## GENERIC TEST CASES ## */ /* ################################################################################################### */ - protected Database generic_create(DatabaseCreateDto createDto, Database database) throws DataServiceException, + protected Database generic_create() throws DataServiceException, DataServiceConnectionException, UserNotFoundException, DatabaseNotFoundException, ContainerNotFoundException, SearchServiceException, SearchServiceConnectionException { @@ -312,13 +275,11 @@ public class DatabaseServiceUnitTest extends AbstractUnitTest { when(searchServiceGateway.update(any(Database.class))) .thenReturn(DATABASE_1_DTO); when(databaseRepository.save(any(Database.class))) - .thenReturn(database); + .thenReturn(DATABASE_1); /* test */ - final Database response = databaseService.create(createDto, USER_1); - assertEquals(database.getName(), response.getName()); - assertEquals(database.getIsPublic(), response.getIsPublic()); - assertTrue(response.getInternalName().startsWith(database.getInternalName())); + final Database response = databaseService.create(CONTAINER_1, DATABASE_1_CREATE, USER_1); + assertTrue(response.getInternalName().startsWith(DATABASE_1_INTERNALNAME)); assertNotNull(response.getContainer()); assertNotNull(response.getTables()); assertNotNull(response.getViews()); @@ -332,7 +293,6 @@ public class DatabaseServiceUnitTest extends AbstractUnitTest { assertNotNull(response.getOwner()); assertNull(response.getImage()); assertNotNull(response.getExchangeName()); - assertEquals(database.getIsPublic(), response.getIsPublic()); return response; } diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/IdentifierServicePersistenceTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/IdentifierServicePersistenceTest.java index 6b3ff624b0e5ebf47757824f645e4a120e43b243..246ae7de1a4beb7a55f4cadf13f142b48ef995fd 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/IdentifierServicePersistenceTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/IdentifierServicePersistenceTest.java @@ -73,8 +73,8 @@ public class IdentifierServicePersistenceTest extends AbstractUnitTest { genesis(); /* metadata database */ licenseRepository.save(LICENSE_1); - containerRepository.saveAll(List.of(CONTAINER_1, CONTAINER_2, CONTAINER_3, CONTAINER_4)); userRepository.saveAll(List.of(USER_1, USER_2, USER_3, USER_4, USER_5)); + containerRepository.saveAll(List.of(CONTAINER_1, CONTAINER_2, CONTAINER_3, CONTAINER_4)); databaseRepository.saveAll(List.of(DATABASE_1, DATABASE_2, DATABASE_3, DATABASE_4)); } diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ImageServicePersistenceTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ImageServicePersistenceTest.java index 50e0dc08f657fb5230838397c90a21a619d8bd8b..fb501cb28179e895dfcf4340afb7dc0cfee547fb 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ImageServicePersistenceTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ImageServicePersistenceTest.java @@ -1,12 +1,12 @@ package at.tuwien.service; +import at.tuwien.exception.ImageInvalidException; import at.tuwien.test.AbstractUnitTest; import at.tuwien.api.container.image.ImageCreateDto; import at.tuwien.exception.ImageAlreadyExistsException; import at.tuwien.repository.ContainerRepository; import at.tuwien.repository.ImageRepository; import lombok.extern.log4j.Log4j2; -import org.apache.http.auth.BasicUserPrincipal; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -15,8 +15,6 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.junit.jupiter.SpringExtension; -import java.security.Principal; - import static org.junit.jupiter.api.Assertions.*; @Log4j2 @@ -42,7 +40,7 @@ public class ImageServicePersistenceTest extends AbstractUnitTest { } @Test - public void create_succeeds() throws ImageAlreadyExistsException { + public void create_succeeds() throws ImageAlreadyExistsException, ImageInvalidException { final ImageCreateDto request = ImageCreateDto.builder() .name(IMAGE_1_NAME) .version("11.1.4") // new tag @@ -51,11 +49,11 @@ public class ImageServicePersistenceTest extends AbstractUnitTest { .dialect(IMAGE_1_DIALECT) .driverClass(IMAGE_1_DRIVER) .defaultPort(IMAGE_1_PORT) + .isDefault(false) .build(); - final Principal principal = new BasicUserPrincipal(USER_1_USERNAME); /* test */ - imageService.create(request, principal); + imageService.create(request, USER_1_PRINCIPAL); } @Test @@ -67,12 +65,31 @@ public class ImageServicePersistenceTest extends AbstractUnitTest { .driverClass(IMAGE_1_DRIVER) .jdbcMethod(IMAGE_1_JDBC) .dialect(IMAGE_1_DIALECT) + .isDefault(IMAGE_1_IS_DEFAULT) .build(); - final Principal principal = new BasicUserPrincipal(USER_1_USERNAME); /* test */ assertThrows(ImageAlreadyExistsException.class, () -> { - imageService.create(request, principal); + imageService.create(request, USER_1_PRINCIPAL); + }); + } + + @Test + public void create_multipleDefaultImages_fails() { + final ImageCreateDto request = ImageCreateDto.builder() + .name("mariadb") + .version("10.5") + .registry(IMAGE_1_REGISTRY) + .defaultPort(IMAGE_1_PORT) + .driverClass(IMAGE_1_DRIVER) + .jdbcMethod(IMAGE_1_JDBC) + .dialect(IMAGE_1_DIALECT) + .isDefault(true) // <<<< + .build(); + + /* test */ + assertThrows(ImageInvalidException.class, () -> { + imageService.create(request, USER_1_PRINCIPAL); }); } diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ImageServiceUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ImageServiceUnitTest.java index bce3c7bc125636591d86a83311a4315ab677fba3..725d956f570e7ed6678047b4bb9d7baf85cbe33b 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ImageServiceUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ImageServiceUnitTest.java @@ -1,5 +1,6 @@ package at.tuwien.service; +import at.tuwien.exception.ImageInvalidException; import at.tuwien.exception.ImageNotFoundException; import at.tuwien.test.AbstractUnitTest; import at.tuwien.api.container.image.ImageChangeDto; @@ -9,6 +10,7 @@ import at.tuwien.exception.ImageAlreadyExistsException; import at.tuwien.repository.ImageRepository; import at.tuwien.service.impl.ImageServiceImpl; import jakarta.validation.ConstraintViolationException; +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; @@ -33,6 +35,11 @@ public class ImageServiceUnitTest extends AbstractUnitTest { @Autowired private ImageService imageService; + @BeforeEach + public void beforeEach() { + genesis(); + } + @Test public void getAll_succeeds() { @@ -82,8 +89,8 @@ public class ImageServiceUnitTest extends AbstractUnitTest { .build(); /* mock */ - when(imageRepository.save(any(ContainerImage.class))) - .thenThrow(ConstraintViolationException.class); + when(imageRepository.findByNameAndVersion(IMAGE_1_NAME, IMAGE_1_VERSION)) + .thenReturn(Optional.of(IMAGE_1)); /* test */ assertThrows(ImageAlreadyExistsException.class, () -> { @@ -91,6 +98,27 @@ public class ImageServiceUnitTest extends AbstractUnitTest { }); } + @Test + public void create_multipleDefaults_fails() { + final ImageCreateDto request = ImageCreateDto.builder() + .name(IMAGE_1_NAME) + .version("10.5") + .defaultPort(IMAGE_1_PORT) + .isDefault(true) + .build(); + + /* mock */ + when(imageRepository.findByNameAndVersion(IMAGE_1_NAME, IMAGE_1_VERSION)) + .thenReturn(Optional.empty()); + when(imageRepository.findByIsDefault(true)) + .thenReturn(Optional.of(IMAGE_1)); + + /* test */ + assertThrows(ImageInvalidException.class, () -> { + imageService.create(request, USER_1_PRINCIPAL); + }); + } + @Test public void update_succeeds() { final ImageServiceImpl mockImageService = mock(ImageServiceImpl.class); diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/MetadataServiceUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/MetadataServiceUnitTest.java index 24ed0f686e8c9885fb4e4b637b6e02a5fc664a48..fa10d09a877c5a967086f855efd091eee1f5efe2 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/MetadataServiceUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/MetadataServiceUnitTest.java @@ -16,6 +16,7 @@ import at.tuwien.gateway.RorGateway; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.log4j.Log4j2; +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; @@ -59,6 +60,11 @@ public class MetadataServiceUnitTest extends AbstractUnitTest { @Autowired private ObjectMapper objectMapper; + @BeforeEach + public void beforeEach() { + genesis(); + } + @Test public void identify_succeeds() { diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/TableServicePersistenceTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/TableServicePersistenceTest.java index e66d35d8ea0d8b0f9aff850cf4baf880e4240c12..7aa22159c395046548324a714d7d8274fc8114af 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/TableServicePersistenceTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/TableServicePersistenceTest.java @@ -71,8 +71,8 @@ public class TableServicePersistenceTest extends AbstractUnitTest { genesis(); /* metadata database */ licenseRepository.save(LICENSE_1); - containerRepository.save(CONTAINER_1); userRepository.saveAll(List.of(USER_1, USER_2, USER_3)); + containerRepository.save(CONTAINER_1); databaseRepository.saveAll(List.of(DATABASE_1)); } @@ -92,7 +92,6 @@ public class TableServicePersistenceTest extends AbstractUnitTest { .name("date") .nullAllowed(true) .type(ColumnTypeDto.DATE) - .dfid(3L) .build())) .constraints(ConstraintsCreateDto.builder() .checks(Set.of()) @@ -124,8 +123,6 @@ public class TableServicePersistenceTest extends AbstractUnitTest { assertEquals("date", date.getName()); assertEquals("date", date.getInternalName()); assertEquals(TableColumnType.DATE, date.getColumnType()); - assertNotNull(date.getDateFormat()); - assertEquals(3L, date.getDateFormat().getId()); assertTrue(date.getIsNullAllowed()); assertNotNull(response.getConstraints()); final List<Unique> uniques = response.getConstraints().getUniques(); diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/TableServiceUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/TableServiceUnitTest.java index 59419f9bad37d26687342c51da6155463d674e87..551a6c350a95e1c9a22fb55d72e04530386cb522 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/TableServiceUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/TableServiceUnitTest.java @@ -5,16 +5,16 @@ import at.tuwien.api.database.table.columns.ColumnCreateDto; import at.tuwien.api.database.table.columns.ColumnTypeDto; import at.tuwien.api.database.table.constraints.ConstraintsCreateDto; import at.tuwien.api.database.table.constraints.foreign.ForeignKeyCreateDto; -import at.tuwien.entities.database.table.columns.TableColumnType; -import at.tuwien.entities.database.table.constraints.Constraints; -import at.tuwien.test.AbstractUnitTest; import at.tuwien.entities.database.Database; import at.tuwien.entities.database.table.Table; import at.tuwien.entities.database.table.columns.TableColumn; +import at.tuwien.entities.database.table.columns.TableColumnType; +import at.tuwien.entities.database.table.constraints.Constraints; import at.tuwien.exception.*; import at.tuwien.gateway.DataServiceGateway; import at.tuwien.gateway.SearchServiceGateway; import at.tuwien.repository.DatabaseRepository; +import at.tuwien.test.AbstractUnitTest; import lombok.extern.log4j.Log4j2; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -49,9 +49,6 @@ public class TableServiceUnitTest extends AbstractUnitTest { @MockBean private DataServiceGateway dataServiceGateway; - @MockBean - private OntologyService ontologyService; - @Autowired private TableService tableService; @@ -179,7 +176,6 @@ public class TableServiceUnitTest extends AbstractUnitTest { assertEquals("i_am_spa_shu_l", column0.getInternalName()); assertEquals(TableColumnType.TEXT, column0.getColumnType()); assertTrue(column0.getIsNullAllowed()); - assertFalse(column0.getAutoGenerated()); /* constraints */ final Constraints constraints = response.getConstraints(); assertEquals(0, constraints.getPrimaryKey().size()); @@ -202,7 +198,6 @@ public class TableServiceUnitTest extends AbstractUnitTest { .name("date") .nullAllowed(true) .type(ColumnTypeDto.DATE) - .dfid(9999L) .build())) .constraints(ConstraintsCreateDto.builder() .checks(Set.of()) diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/UserServiceUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/UserServiceUnitTest.java index 5becb9225a42db3ab451dc054663e811e7c71629..a9fe4694cc69d8eb347e9fefd12498704b8797fd 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/UserServiceUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/UserServiceUnitTest.java @@ -5,6 +5,7 @@ import at.tuwien.entities.user.User; import at.tuwien.exception.*; import at.tuwien.gateway.KeycloakGateway; import at.tuwien.repository.UserRepository; +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; @@ -32,6 +33,11 @@ public class UserServiceUnitTest extends AbstractUnitTest { @Autowired private UserService userService; + @BeforeEach + public void beforeEach() { + genesis(); + } + @Test public void findByUsername_succeeds() throws UserNotFoundException { diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ViewServicePersistenceTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ViewServicePersistenceTest.java index e23320017c54592662f42b24c3eb7039a3f1a540..8ca002472a085a58ea5ee58fff8a2a0614c94fd9 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ViewServicePersistenceTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ViewServicePersistenceTest.java @@ -2,6 +2,7 @@ package at.tuwien.service; import at.tuwien.entities.database.Database; import at.tuwien.entities.database.View; +import at.tuwien.entities.database.ViewColumn; import at.tuwien.exception.*; import at.tuwien.gateway.DataServiceGateway; import at.tuwien.gateway.SearchServiceGateway; @@ -24,6 +25,7 @@ import org.springframework.test.context.junit.jupiter.SpringExtension; import java.util.List; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.when; @@ -61,9 +63,9 @@ public class ViewServicePersistenceTest extends AbstractUnitTest { genesis(); /* metadata database */ licenseRepository.save(LICENSE_1); - containerRepository.save(CONTAINER_1); userRepository.saveAll(List.of(USER_1, USER_2, USER_3)); - databaseRepository.save(DATABASE_1); + containerRepository.save(CONTAINER_1); + databaseRepository.saveAll(List.of(DATABASE_1, DATABASE_2, DATABASE_3)); } @Test @@ -91,6 +93,9 @@ public class ViewServicePersistenceTest extends AbstractUnitTest { /* test */ viewService.delete(VIEW_1); + assertThrows(ViewNotFoundException.class, () -> { + viewService.findById(DATABASE_1, VIEW_1_ID); + }); } } diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/validator/EndpointValidatorUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/validator/EndpointValidatorUnitTest.java index f6cf4e887d4d25f2dfc201ae6d4d014f3b8c1547..8528d29f07d267bd4dcbe94de5379e47e13f1cef 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/validator/EndpointValidatorUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/validator/EndpointValidatorUnitTest.java @@ -53,30 +53,9 @@ public class EndpointValidatorUnitTest extends AbstractUnitTest { public static Stream<Arguments> needSize_parameters() { return Stream.of( - Arguments.arguments(ColumnTypeDto.CHAR), Arguments.arguments(ColumnTypeDto.VARCHAR), Arguments.arguments(ColumnTypeDto.BINARY), - Arguments.arguments(ColumnTypeDto.VARBINARY), - Arguments.arguments(ColumnTypeDto.BIT), - Arguments.arguments(ColumnTypeDto.TINYINT), - Arguments.arguments(ColumnTypeDto.SMALLINT), - Arguments.arguments(ColumnTypeDto.MEDIUMINT), - Arguments.arguments(ColumnTypeDto.INT) - ); - } - - public static Stream<Arguments> needSizeAndD_parameters() { - return Stream.of( - Arguments.arguments(ColumnTypeDto.DOUBLE), - Arguments.arguments(ColumnTypeDto.DECIMAL) - ); - } - - public static Stream<Arguments> needDateFormat_parameters() { - return Stream.of( - Arguments.arguments(ColumnTypeDto.DATETIME), - Arguments.arguments(ColumnTypeDto.TIMESTAMP), - Arguments.arguments(ColumnTypeDto.TIME) + Arguments.arguments(ColumnTypeDto.VARBINARY) ); } @@ -308,23 +287,6 @@ public class EndpointValidatorUnitTest extends AbstractUnitTest { }); } - @ParameterizedTest - @MethodSource("needSizeAndD_parameters") - public void validateColumnCreateConstraints_needSizeAndD_fails(ColumnTypeDto type) { - final TableCreateDto request = TableCreateDto.builder() - .columns(List.of(ColumnCreateDto.builder() - .type(type) - .size(10L) - .d(null) // <<<<<<< - .build())) - .build(); - - /* test */ - assertThrows(MalformedException.class, () -> { - endpointValidator.validateColumnCreateConstraints(request); - }); - } - @Test public void validateColumnCreateConstraints_needEnum_fails() { final TableCreateDto request = TableCreateDto.builder() @@ -355,35 +317,6 @@ public class EndpointValidatorUnitTest extends AbstractUnitTest { }); } - @ParameterizedTest - @MethodSource("needDateFormat_parameters") - public void validateColumnCreateConstraints_needDateFormat_fails(ColumnTypeDto type) { - final TableCreateDto request = TableCreateDto.builder() - .columns(List.of(ColumnCreateDto.builder() - .type(type) - .dfid(null) // <<<<<<< - .build())) - .build(); - - /* test */ - assertThrows(MalformedException.class, () -> { - endpointValidator.validateColumnCreateConstraints(request); - }); - } - - @Test - public void validateColumnCreateConstraints_dateFormatEmpty_succeeds() throws MalformedException { - final TableCreateDto request = TableCreateDto.builder() - .columns(List.of(ColumnCreateDto.builder() - .type(ColumnTypeDto.DATE) - .dfid(null) // <<<<<<< - .build())) - .build(); - - /* test */ - endpointValidator.validateColumnCreateConstraints(request); - } - @Test public void validateOnlyOwnerOrWriteAll_onlyReadAccess_fails() throws DatabaseNotFoundException, TableNotFoundException, AccessNotFoundException { diff --git a/dbrepo-metadata-service/services/pom.xml b/dbrepo-metadata-service/services/pom.xml index bf2105f98da2ff1644bd94493f54f1b5929ea9ce..744a4e6def94c9ff67a24bea56375c0c7fb076d1 100644 --- a/dbrepo-metadata-service/services/pom.xml +++ b/dbrepo-metadata-service/services/pom.xml @@ -6,12 +6,12 @@ <parent> <artifactId>dbrepo-metadata-service</artifactId> <groupId>at.tuwien</groupId> - <version>1.4.5</version> + <version>1.4.7</version> </parent> <artifactId>dbrepo-metadata-service-services</artifactId> <name>dbrepo-metadata-service-services</name> - <version>1.4.5</version> + <version>1.4.7</version> <dependencies> <dependency> diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/MetricsConfig.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/MetricsConfig.java index 450be2f7df8b52fe493dd498dc0422350bb3ff39..1b7578b4bcdb547eae2cc26690ef028c38367787 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/MetricsConfig.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/MetricsConfig.java @@ -1,13 +1,82 @@ package at.tuwien.config; +import at.tuwien.entities.database.table.Table; +import at.tuwien.repository.DatabaseRepository; +import at.tuwien.repository.IdentifierRepository; +import at.tuwien.repository.TableRepository; +import at.tuwien.repository.ViewRepository; +import io.micrometer.core.instrument.Gauge; +import io.micrometer.core.instrument.Metrics; import io.micrometer.observation.ObservationRegistry; import io.micrometer.observation.aop.ObservedAspect; +import lombok.extern.log4j.Log4j2; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +@Log4j2 @Configuration public class MetricsConfig { + private final ViewRepository viewRepository; + private final TableRepository tableRepository; + private final DatabaseRepository databaseRepository; + private final IdentifierRepository identifierRepository; + + @Autowired + public MetricsConfig(ViewRepository viewRepository, TableRepository tableRepository, + DatabaseRepository databaseRepository, IdentifierRepository identifierRepository) { + this.viewRepository = viewRepository; + this.tableRepository = tableRepository; + this.databaseRepository = databaseRepository; + this.identifierRepository = identifierRepository; + } + + @Bean + public Gauge databaseCountGauge() { + return Gauge.builder("dbrepo.database.count", () -> databaseRepository.findAll().size()) + .description("The total number of managed research databases") + .strongReference(true) + .register(Metrics.globalRegistry); + } + + @Bean + public Gauge viewCountGauge() { + return Gauge.builder("dbrepo.view.count", () -> viewRepository.findAll().size()) + .description("The total number of available view data sources") + .strongReference(true) + .register(Metrics.globalRegistry); + } + + @Bean + public Gauge subsetCountGauge() { + return Gauge.builder("dbrepo.subset.count", () -> identifierRepository.findAllSubsetIdentifiers().size()) + .description("The total number of available subset data sources") + .strongReference(true) + .register(Metrics.globalRegistry); + } + + @Bean + public Gauge tableCountGauge() { + return Gauge.builder("dbrepo.table.count", () -> tableRepository.findAll().size()) + .description("The total number of available table data sources") + .strongReference(true) + .register(Metrics.globalRegistry); + } + + @Bean + public Gauge volumeSumGauge() { + return Gauge.builder("dbrepo.volume.sum", () -> { + if (tableRepository.findAll().isEmpty()) { + return 0; + } + return tableRepository.findAll().stream().map(Table::getDataLength).mapToLong(d -> d).sum(); + }) + .description("The total volume of available research data") + .strongReference(true) + .register(Metrics.globalRegistry); + } + @Bean public ObservedAspect observedAspect(ObservationRegistry observationRegistry) { return new ObservedAspect(observationRegistry); diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/DataServiceGatewayImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/DataServiceGatewayImpl.java index 886911d9f4a770fe8c620d7cc882cd7b4da05c55..709537862a77b5bb6bccb5be4cae5d26f5622121 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/DataServiceGatewayImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/DataServiceGatewayImpl.java @@ -214,7 +214,7 @@ public class DataServiceGatewayImpl implements DataServiceGateway { public ViewDto createView(Long databaseId, ViewCreateDto data) throws DataServiceConnectionException, DataServiceException { final ResponseEntity<ViewDto> response; final String path = "/api/database/" + databaseId + "/view"; - log.trace("delete table at endpoint {} with path {}", gatewayConfig.getDataEndpoint(), path); + log.trace("create view at endpoint {} with path {}", gatewayConfig.getDataEndpoint(), path); try { response = restTemplate.exchange(path, HttpMethod.POST, new HttpEntity<>(data), ViewDto.class); } catch (HttpServerErrorException e) { @@ -264,6 +264,7 @@ public class DataServiceGatewayImpl implements DataServiceGateway { QueryNotFoundException { final ResponseEntity<QueryDto> response; final String path = "/api/database/" + databaseId + "/subset/" + queryId; + log.trace("find subset at endpoint {} with path {}", gatewayConfig.getDataEndpoint(), path); try { response = restTemplate.exchange(path, HttpMethod.GET, HttpEntity.EMPTY, QueryDto.class); } catch (HttpServerErrorException e) { @@ -291,6 +292,7 @@ public class DataServiceGatewayImpl implements DataServiceGateway { DataServiceException, QueryNotFoundException { final ResponseEntity<ExportResourceDto> response; final String path = "/api/database/" + databaseId + "/subset/" + queryId; + log.trace("export subset at endpoint {} with path {}", gatewayConfig.getDataEndpoint(), path); try { response = restTemplate.exchange(path, HttpMethod.GET, HttpEntity.EMPTY, ExportResourceDto.class); } catch (HttpServerErrorException e) { @@ -315,6 +317,7 @@ public class DataServiceGatewayImpl implements DataServiceGateway { TableNotFoundException { final ResponseEntity<TableDto[]> response; final String path = "/api/database/" + databaseId + "/table"; + log.trace("get table schemas at endpoint {} with path {}", gatewayConfig.getDataEndpoint(), path); try { response = restTemplate.exchange(path, HttpMethod.GET, HttpEntity.EMPTY, TableDto[].class); } catch (HttpServerErrorException e) { @@ -372,7 +375,8 @@ public class DataServiceGatewayImpl implements DataServiceGateway { } @Override - public TableStatisticDto getTableStatistics(Long databaseId, Long tableId) throws DataServiceConnectionException, DataServiceException, TableNotFoundException { + public TableStatisticDto getTableStatistics(Long databaseId, Long tableId) throws DataServiceConnectionException, + DataServiceException, TableNotFoundException { final ResponseEntity<TableStatisticDto> response; final String path = "/api/database/" + databaseId + "/table/" + tableId + "/statistic"; log.trace("get table statistics at endpoint {} with path {}", gatewayConfig.getDataEndpoint(), path); @@ -392,10 +396,6 @@ public class DataServiceGatewayImpl implements DataServiceGateway { log.error("Failed to analyse table statistic: wrong http code: {}", response.getStatusCode()); throw new DataServiceException("Failed to analyse table statistic: wrong http code: " + response.getStatusCode()); } - if (response.getBody() == null) { - log.error("Failed to analyse table statistic: empty body: {}", response.getStatusCode()); - throw new DataServiceException("Failed to analyse table statistic: empty body: " + response.getStatusCode()); - } return response.getBody(); } diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/DatabaseService.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/DatabaseService.java index aa25ee1362f825ddf060ce9c90dde9e4c965b6bf..d7c036049b84cfe9d028fa60fa532aa6ba00dc75 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/DatabaseService.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/DatabaseService.java @@ -2,6 +2,7 @@ package at.tuwien.service; import at.tuwien.api.database.DatabaseCreateDto; import at.tuwien.api.database.DatabaseModifyVisibilityDto; +import at.tuwien.entities.container.Container; import at.tuwien.entities.database.Database; import at.tuwien.entities.user.User; import at.tuwien.exception.*; @@ -47,15 +48,17 @@ public interface DatabaseService { /** * Creates a new database with minimal metadata in the metadata database and creates a new database on the container. * + * @param container The container. * @param createDto The metadata. * @param user The user. * @return The database, if successful. - * @throws UserNotFoundException If the container/user was not found in the metadata database. + * @throws UserNotFoundException If the container/user was not found in the metadata database. * @throws DataServiceException If the data service returned non-successfully. * @throws DataServiceConnectionException If failing to connect to the data service/search service. */ - Database create(DatabaseCreateDto createDto, User user) throws UserNotFoundException, ContainerNotFoundException, - DataServiceException, DataServiceConnectionException, DatabaseNotFoundException, SearchServiceException, SearchServiceConnectionException; + Database create(Container container, DatabaseCreateDto createDto, User user) throws UserNotFoundException, + ContainerNotFoundException, DataServiceException, DataServiceConnectionException, DatabaseNotFoundException, + SearchServiceException, SearchServiceConnectionException; /** * Updates the user's password. @@ -73,7 +76,7 @@ public interface DatabaseService { * @param database The database. * @param data The visibility * @return The database, if successful. - * @throws NotFoundException The database was not found in the metadata database. + * @throws NotFoundException The database was not found in the metadata database. * @throws DataServiceConnectionException If failing to connect to the search service. */ Database modifyVisibility(Database database, DatabaseModifyVisibilityDto data) throws DatabaseNotFoundException, SearchServiceException, SearchServiceConnectionException; diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/ImageService.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/ImageService.java index bb5134ebc4f1435f9db797f54b0128ab2cff9bbb..cc51082d65f1b72a066208b83276169fd36d8f5d 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/ImageService.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/ImageService.java @@ -4,6 +4,7 @@ import at.tuwien.api.container.image.ImageChangeDto; import at.tuwien.api.container.image.ImageCreateDto; import at.tuwien.entities.container.image.ContainerImage; import at.tuwien.exception.ImageAlreadyExistsException; +import at.tuwien.exception.ImageInvalidException; import at.tuwien.exception.ImageNotFoundException; import java.security.Principal; @@ -32,8 +33,11 @@ public interface ImageService { * @param createDto The new image. * @param principal The user principal. * @return The container image, if successful. + * @throws ImageAlreadyExistsException The image already exists. + * @throws ImageInvalidException The default image cannot be created as a default image already exists. */ - ContainerImage create(ImageCreateDto createDto, Principal principal) throws ImageAlreadyExistsException; + ContainerImage create(ImageCreateDto createDto, Principal principal) throws ImageAlreadyExistsException, + ImageInvalidException; /** * Updates a container image with given id in the metadata database. diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/UserService.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/UserService.java index 92e0bc37ee2b58eddc9faa86f08d4748caf662f5..8e7c715ad06d434bfdb947136546f686e91835ad 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/UserService.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/UserService.java @@ -76,4 +76,6 @@ public interface UserService { * @throws EmailExistsException The user with this email already exists. */ void validateEmailNotExists(String email) throws EmailExistsException; + + String getMariaDbPassword(String password); } diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/AccessServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/AccessServiceImpl.java index aaa50251c3dc0dd79e51af1c983bfda07affffaa..b6af9018118f0e502feb1452b8a4838e9baadb34 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/AccessServiceImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/AccessServiceImpl.java @@ -73,6 +73,7 @@ public class AccessServiceImpl implements AccessService { .database(database) .huserid(user.getId()) .type(metadataMapper.accessTypeDtoToAccessType(type)) + .user(user) .build(); database.getAccesses() .add(access); @@ -95,8 +96,8 @@ public class AccessServiceImpl implements AccessService { .hdbid(database.getId()) .database(database) .huserid(user.getId()) - .user(user) .type(metadataMapper.accessTypeDtoToAccessType(access)) + .user(user) .build(); final int idx = database.getAccesses().indexOf(entity); if (idx == -1) { diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/DatabaseServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/DatabaseServiceImpl.java index 8c835864db5ed4bf69bd2bd6b29adfe4d409899d..330d4518dedba7e1e5e78f25a7433c18762fd579 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/DatabaseServiceImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/DatabaseServiceImpl.java @@ -11,9 +11,11 @@ import at.tuwien.entities.container.Container; import at.tuwien.entities.database.*; import at.tuwien.entities.database.table.Table; import at.tuwien.entities.database.table.columns.TableColumn; +import at.tuwien.entities.database.table.constraints.Constraints; import at.tuwien.entities.database.table.constraints.foreignKey.ForeignKey; import at.tuwien.entities.database.table.constraints.foreignKey.ForeignKeyReference; import at.tuwien.entities.database.table.constraints.primaryKey.PrimaryKey; +import at.tuwien.entities.database.table.constraints.unique.Unique; import at.tuwien.entities.user.User; import at.tuwien.exception.*; import at.tuwien.gateway.DataServiceGateway; @@ -34,17 +36,14 @@ import java.util.*; public class DatabaseServiceImpl implements DatabaseService { private final MetadataMapper metadataMapper; - private final ContainerService containerService; private final DatabaseRepository databaseRepository; private final DataServiceGateway dataServiceGateway; private final SearchServiceGateway searchServiceGateway; @Autowired - public DatabaseServiceImpl(MetadataMapper metadataMapper, ContainerService containerService, - DatabaseRepository databaseRepository, DataServiceGateway dataServiceGateway, - SearchServiceGateway searchServiceGateway) { + public DatabaseServiceImpl(MetadataMapper metadataMapper, DatabaseRepository databaseRepository, + DataServiceGateway dataServiceGateway, SearchServiceGateway searchServiceGateway) { this.metadataMapper = metadataMapper; - this.containerService = containerService; this.databaseRepository = databaseRepository; this.dataServiceGateway = dataServiceGateway; this.searchServiceGateway = searchServiceGateway; @@ -84,10 +83,9 @@ public class DatabaseServiceImpl implements DatabaseService { @Override @Transactional - public Database create(DatabaseCreateDto data, User user) throws UserNotFoundException, + public Database create(Container container, DatabaseCreateDto data, User user) throws UserNotFoundException, ContainerNotFoundException, DataServiceException, DataServiceConnectionException, DatabaseNotFoundException, SearchServiceException, SearchServiceConnectionException { - final Container container = containerService.find(data.getCid()); Database database = Database.builder() .isPublic(data.getIsPublic()) .name(data.getName()) @@ -169,7 +167,10 @@ public class DatabaseServiceImpl implements DatabaseService { public Database modifyOwner(Database database, User user) throws DatabaseNotFoundException, SearchServiceException, SearchServiceConnectionException { /* update in metadata database */ + database.setOwner(user); database.setOwnedBy(user.getId()); + database.setContact(user); + database.setContactPerson(user.getId()); database = databaseRepository.save(database); /* save in search service */ searchServiceGateway.update(database); @@ -216,12 +217,14 @@ public class DatabaseServiceImpl implements DatabaseService { .forEach(column -> { column.setTable(tableEntity); }); + log.trace("mapped unique constraint: {} ({})", tableEntity.getName(), uk.getColumns().stream().map(TableColumn::getInternalName).toList()); }); /* map foreign key constraint(s) */ tableEntity.getConstraints() .getForeignKeys() .forEach(fk -> { fk.setTable(tableEntity); + log.trace("mapped foreign key constraint: {} ({}) -> {} ({})", fk.getTable().getInternalName(), fk.getReferences().stream().map(r -> r.getColumn().getInternalName()).toList(), fk.getReferencedTable().getInternalName(), fk.getReferences().stream().map(r -> r.getReferencedColumn().getInternalName()).toList()); }); /* map primary key constraint */ for (PrimaryKey key : tableEntity.getConstraints().getPrimaryKey()) { @@ -241,7 +244,6 @@ public class DatabaseServiceImpl implements DatabaseService { } /* update referenced tables after they are known to the service */ for (ForeignKey foreignKey : database.getTables().stream().map(t -> t.getConstraints().getForeignKeys()).flatMap(List::stream).toList()) { - log.trace("lookup table {} in tables: {}", foreignKey.getReferencedTable().getInternalName(), database.getTables().stream().map(Table::getInternalName).toList()); final Optional<Table> optional = database.getTables() .stream() .filter(t -> t.getInternalName().equals(foreignKey.getReferencedTable().getInternalName())) @@ -279,15 +281,25 @@ public class DatabaseServiceImpl implements DatabaseService { reference.setReferencedColumn(optional2.get()); } } - database.getTables() - .stream() - .filter(t -> t.getConstraints().getForeignKeys().size() > 0) - .map(t -> t.getConstraints().getForeignKeys()) - .flatMap(List::stream) - .filter(fk -> fk.getReferences().size() > 1) - .forEach(fk -> { - log.debug(""); - }); + /* correct the unique constraint columns */ + for (Table table : database.getTables()) { + for (Unique uniqueConstraint : table.getConstraints().getUniques()) { + uniqueConstraint.setColumns(new LinkedList<>(uniqueConstraint.getColumns() + .stream() + .map(column -> { + final Optional<TableColumn> optional = table.getColumns() + .stream() + .filter(c -> c.getInternalName().equals(column.getInternalName())) + .findFirst(); + if (optional.isEmpty()) { + log.error("Failed to find unique constraint column: {}", column.getInternalName()); + throw new IllegalArgumentException("Failed to find unique constraint column: " + column.getInternalName()); + } + return optional.get(); + }) + .toList())); + } + } /* update in metadata database */ database = databaseRepository.save(database); /* save in search service */ diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ImageServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ImageServiceImpl.java index 8e4decfc1724a010e4d62f38491ad3404d259b1d..84fdffcf43b1e6e6f110bf0acf72d4ca75a3a3cf 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ImageServiceImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ImageServiceImpl.java @@ -4,6 +4,7 @@ import at.tuwien.api.container.image.ImageChangeDto; import at.tuwien.api.container.image.ImageCreateDto; import at.tuwien.entities.container.image.ContainerImage; import at.tuwien.exception.ImageAlreadyExistsException; +import at.tuwien.exception.ImageInvalidException; import at.tuwien.exception.ImageNotFoundException; import at.tuwien.mapper.MetadataMapper; import at.tuwien.repository.ImageRepository; @@ -51,13 +52,17 @@ public class ImageServiceImpl implements ImageService { @Override @Transactional - public ContainerImage create(ImageCreateDto createDto, Principal principal) throws ImageAlreadyExistsException { + public ContainerImage create(ImageCreateDto createDto, Principal principal) throws ImageAlreadyExistsException, + ImageInvalidException { final ContainerImage image = metadataMapper.createImageDtoToContainerImage(createDto); if (imageRepository.findByNameAndVersion(createDto.getName(), createDto.getVersion()).isPresent()) { - log.error("Failed to create image {}:{}: exists in the metadata database", - createDto.getName(), createDto.getVersion()); + log.error("Failed to create image {}:{}: exists in the metadata database", createDto.getName(), createDto.getVersion()); throw new ImageAlreadyExistsException("Failed to create image " + createDto.getName() + ":" + createDto.getVersion() + ": exists in the metadata database"); } + if (createDto.getIsDefault() && imageRepository.findByIsDefault(true).isPresent()) { + log.error("Failed to create image {}:{}: default image exists", createDto.getName(), createDto.getVersion()); + throw new ImageInvalidException("Failed to create image: default image exists"); + } final ContainerImage dto; try { dto = imageRepository.save(image); diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/TableServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/TableServiceImpl.java index 85723725161007ffdafd36450624ed6e1afdbe1a..550cde69a864397d4bf1328a9daf3543f2a3361a 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/TableServiceImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/TableServiceImpl.java @@ -4,16 +4,13 @@ import at.tuwien.api.database.table.TableCreateDto; import at.tuwien.api.database.table.TableStatisticDto; import at.tuwien.api.database.table.columns.ColumnCreateDto; import at.tuwien.api.database.table.columns.ColumnStatisticDto; -import at.tuwien.api.database.table.columns.ColumnTypeDto; import at.tuwien.api.database.table.columns.concepts.ColumnSemanticsUpdateDto; import at.tuwien.api.semantics.EntityDto; import at.tuwien.config.RabbitConfig; -import at.tuwien.entities.container.image.ContainerImageDate; import at.tuwien.entities.database.Database; import at.tuwien.entities.database.table.Table; import at.tuwien.entities.database.table.columns.TableColumn; import at.tuwien.entities.database.table.columns.TableColumnConcept; -import at.tuwien.entities.database.table.columns.TableColumnType; import at.tuwien.entities.database.table.columns.TableColumnUnit; import at.tuwien.entities.user.User; import at.tuwien.exception.*; @@ -28,7 +25,10 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.security.Principal; -import java.util.*; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Optional; @Log4j2 @Service @@ -153,20 +153,6 @@ public class TableServiceImpl implements TableService { log.trace("created concept in metadata database: {}", concept); } } - if (List.of(TableColumnType.TIME, TableColumnType.TIMESTAMP, TableColumnType.DATE, TableColumnType.DATETIME).contains(column.getColumnType())) { - final Optional<ContainerImageDate> optional = database.getContainer() - .getImage() - .getDateFormats() - .stream() - .filter(df -> df.getId().equals(c.getDfid())) - .findFirst(); - if (optional.isEmpty()) { - log.error("Failed to find date format with id {} in metadata database", c.getDfid()); - throw new IllegalArgumentException("Failed to find date format in metadata database"); - } - column.setDateFormat(optional.get()); - log.debug("column is of temporal type: added date format with id {}", column.getDateFormat().getId()); - } table.getColumns() .add(column); } @@ -179,6 +165,8 @@ public class TableServiceImpl implements TableService { for (int i = 0; i < data.getConstraints().getUniques().size(); i++) { if (data.getConstraints().getUniques().get(i).size() != table.getConstraints().getUniques().get(i).getColumns().size()) { log.error("Failed to create table: some unique constraint(s) reference non-existing table columns: {}", data.getConstraints().getUniques().get(i)); + log.debug("payload uniques: {}", data.getConstraints().getUniques()); + log.debug("mapped table uniques: {}", table.getConstraints().getUniques().stream().map(u -> List.of(u.getColumns().stream().map(TableColumn::getInternalName).toList())).toList()); throw new MalformedException("Failed to create table: some unique constraint(s) reference non-existing table columns"); } } @@ -210,7 +198,9 @@ public class TableServiceImpl implements TableService { /* delete at data service */ dataServiceGateway.deleteTable(table.getDatabase().getId(), table.getId()); /* update in metadata database */ - table.getDatabase().getTables().remove(table); + table.getDatabase() + .getTables() + .remove(table); final Database database = databaseRepository.save(table.getDatabase()); /* update in search service */ searchServiceGateway.update(database); @@ -285,6 +275,9 @@ public class TableServiceImpl implements TableService { DatabaseNotFoundException, SearchServiceConnectionException, MalformedException, TableNotFoundException, DataServiceException, DataServiceConnectionException { final TableStatisticDto statistic = dataServiceGateway.getTableStatistics(table.getTdbid(), table.getId()); + if (statistic == null) { + return; + } table.setNumRows(statistic.getRows()); table.setDataLength(statistic.getDataLength()); table.setAvgRowLength(statistic.getAvgRowLength()); diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/UserServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/UserServiceImpl.java index 547a01c2fab73cf410673778747f0545c40907de..7e07b68d1c965ed42261ab508273770be50a6454 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/UserServiceImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/UserServiceImpl.java @@ -105,6 +105,7 @@ public class UserServiceImpl implements UserService { } } + @Override public String getMariaDbPassword(String password) { final byte[] utf8 = password.getBytes(StandardCharsets.UTF_8); return "*" + DigestUtils.sha1Hex(DigestUtils.sha1(utf8)).toUpperCase(); diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ViewServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ViewServiceImpl.java index 0826d9dcc88e344227f56550b2aebd6f42e3494e..17a2c26d8929e6e89d220427100e1124c75b92b8 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ViewServiceImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ViewServiceImpl.java @@ -75,7 +75,9 @@ public class ViewServiceImpl implements ViewService { /* delete in data service */ dataServiceGateway.deleteView(view.getDatabase().getId(), view.getId()); /* delete in metadata database */ - view.getDatabase().getViews().remove(view); + view.getDatabase() + .getViews() + .remove(view); final Database database = databaseRepository.save(view.getDatabase()); /* update in search service */ searchServiceGateway.update(database); diff --git a/dbrepo-metadata-service/test/pom.xml b/dbrepo-metadata-service/test/pom.xml index 2c4091eace14d78e0a6323f8960be5ffa6f5cfb0..a03ae0b3a6d6316c1537a7acff40aa8694db309e 100644 --- a/dbrepo-metadata-service/test/pom.xml +++ b/dbrepo-metadata-service/test/pom.xml @@ -6,12 +6,12 @@ <parent> <groupId>at.tuwien</groupId> <artifactId>dbrepo-metadata-service</artifactId> - <version>1.4.5</version> + <version>1.4.7</version> </parent> <artifactId>dbrepo-metadata-service-test</artifactId> <name>dbrepo-metadata-service-test</name> - <version>1.4.5</version> + <version>1.4.7</version> <dependencies> <dependency> diff --git a/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/AbstractUnitTest.java b/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/AbstractUnitTest.java index 156563a041c833376f850465032f28b69602e020..3ab89a39051326901f9b4029689bf4be82bd177f 100644 --- a/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/AbstractUnitTest.java +++ b/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/AbstractUnitTest.java @@ -9,6 +9,8 @@ import java.util.List; public abstract class AbstractUnitTest extends BaseTest { public void genesis() { + CONTAINER_1.setDatabases(new LinkedList<>(List.of(DATABASE_1, DATABASE_2, DATABASE_3))); + CONTAINER_4.setDatabases(new LinkedList<>(List.of(DATABASE_4))); /* USER_1 */ USER_1.setAccesses(new LinkedList<>()); /* USER_2 */ @@ -20,6 +22,7 @@ public abstract class AbstractUnitTest extends BaseTest { /* USER_4 */ USER_5.setAccesses(new LinkedList<>()); /* DATABASE 1 */ + DATABASE_1.setOwner(USER_1); DATABASE_1.setSubsets(new LinkedList<>()); DATABASE_1.setAccesses(new LinkedList<>(List.of(DATABASE_1_USER_1_READ_ACCESS, DATABASE_1_USER_2_WRITE_OWN_ACCESS, DATABASE_1_USER_3_WRITE_ALL_ACCESS))); DATABASE_1_PRIVILEGED_DTO.setAccesses(new LinkedList<>(List.of(DATABASE_1_USER_1_READ_ACCESS_DTO, DATABASE_1_USER_2_WRITE_OWN_ACCESS_DTO, DATABASE_1_USER_3_WRITE_ALL_ACCESS_DTO))); @@ -35,7 +38,7 @@ public abstract class AbstractUnitTest extends BaseTest { DATABASE_1_PRIVILEGED_DTO.setIdentifiers(new LinkedList<>(List.of(IDENTIFIER_1_DTO, IDENTIFIER_2_DTO, IDENTIFIER_3_DTO, IDENTIFIER_4_DTO))); DATABASE_1_PRIVILEGED_DTO.setTables(new LinkedList<>(List.of(TABLE_1_DTO, TABLE_2_DTO, TABLE_3_DTO, TABLE_4_DTO))); DATABASE_1_PRIVILEGED_DTO.setViews(new LinkedList<>(List.of(VIEW_1_DTO, VIEW_2_DTO, VIEW_3_DTO))); - TABLE_1_DTO.setColumns(TABLE_1_COLUMNS_DTO); + TABLE_1_DTO.setColumns(new LinkedList<>(TABLE_1_COLUMNS_DTO)); TABLE_1_DTO.setConstraints(TABLE_1_CONSTRAINTS_DTO); TABLE_2.setDatabase(DATABASE_1); TABLE_2.setColumns(new LinkedList<>(TABLE_2_COLUMNS)); @@ -43,12 +46,12 @@ public abstract class AbstractUnitTest extends BaseTest { TABLE_2.setConstraints(TABLE_2_CONSTRAINTS); TABLE_2_PRIVILEGED_DTO.setColumns(new LinkedList<>(TABLE_2_COLUMNS_DTO)); TABLE_2_PRIVILEGED_DTO.setDatabase(DATABASE_1_PRIVILEGED_DTO); - TABLE_2_DTO.setColumns(TABLE_2_COLUMNS_DTO); + TABLE_2_DTO.setColumns(new LinkedList<>(TABLE_2_COLUMNS_DTO)); TABLE_2_DTO.setConstraints(TABLE_2_CONSTRAINTS_DTO); TABLE_3.setDatabase(DATABASE_1); TABLE_3.setColumns(new LinkedList<>(TABLE_3_COLUMNS)); TABLE_3.setConstraints(TABLE_3_CONSTRAINTS); - TABLE_3_DTO.setColumns(TABLE_3_COLUMNS_DTO); + TABLE_3_DTO.setColumns(new LinkedList<>(TABLE_3_COLUMNS_DTO)); TABLE_3_DTO.setConstraints(TABLE_3_CONSTRAINTS_DTO); TABLE_4.setDatabase(DATABASE_1); TABLE_4.setColumns(new LinkedList<>(TABLE_4_COLUMNS)); @@ -56,14 +59,14 @@ public abstract class AbstractUnitTest extends BaseTest { TABLE_4_DTO.setColumns(TABLE_4_COLUMNS_DTO); TABLE_4_DTO.setConstraints(TABLE_4_CONSTRAINTS_DTO); VIEW_1.setDatabase(DATABASE_1); - VIEW_1.setColumns(VIEW_1_COLUMNS); + VIEW_1.setColumns(new LinkedList<>(VIEW_1_COLUMNS)); VIEW_1.setIdentifiers(new LinkedList<>(List.of(IDENTIFIER_3))); VIEW_1_PRIVILEGED_DTO.setDatabase(DATABASE_1_PRIVILEGED_DTO); VIEW_2.setDatabase(DATABASE_1); - VIEW_2.setColumns(VIEW_2_COLUMNS); + VIEW_2.setColumns(new LinkedList<>(VIEW_2_COLUMNS)); VIEW_2_PRIVILEGED_DTO.setDatabase(DATABASE_1_PRIVILEGED_DTO); VIEW_3.setDatabase(DATABASE_1); - VIEW_3.setColumns(VIEW_3_COLUMNS); + VIEW_3.setColumns(new LinkedList<>(VIEW_3_COLUMNS)); VIEW_3_PRIVILEGED_DTO.setDatabase(DATABASE_1_PRIVILEGED_DTO); IDENTIFIER_1.setDatabase(DATABASE_1); IDENTIFIER_2.setDatabase(DATABASE_1); @@ -74,6 +77,7 @@ public abstract class AbstractUnitTest extends BaseTest { DATABASE_2.setAccesses(new LinkedList<>(List.of(DATABASE_2_USER_2_WRITE_ALL_ACCESS, DATABASE_2_USER_3_READ_ACCESS))); DATABASE_2_PRIVILEGED_DTO.setAccesses(new LinkedList<>(List.of(DATABASE_2_USER_2_WRITE_ALL_ACCESS_DTO, DATABASE_2_USER_3_READ_ACCESS_DTO))); DATABASE_2.setTables(new LinkedList<>(List.of(TABLE_5, TABLE_6, TABLE_7))); + VIEW_4.setColumns(new LinkedList<>(VIEW_4_COLUMNS)); DATABASE_2.setViews(new LinkedList<>(List.of(VIEW_4))); DATABASE_2.setIdentifiers(new LinkedList<>(List.of(IDENTIFIER_5))); DATABASE_2_PRIVILEGED_DTO.setTables(new LinkedList<>(List.of(TABLE_5_DTO, TABLE_6_DTO, TABLE_7_DTO))); @@ -83,6 +87,7 @@ public abstract class AbstractUnitTest extends BaseTest { TABLE_5.setColumns(new LinkedList<>(TABLE_5_COLUMNS)); TABLE_5.setConstraints(TABLE_5_CONSTRAINTS); TABLE_5_PRIVILEGED_DTO.setColumns(new LinkedList<>(TABLE_5_COLUMNS_DTO)); + TABLE_5_PRIVILEGED_DTO.setConstraints(TABLE_5_CONSTRAINTS_DTO); TABLE_5_PRIVILEGED_DTO.setDatabase(DATABASE_2_PRIVILEGED_DTO); TABLE_5_DTO.setColumns(TABLE_5_COLUMNS_DTO); TABLE_5_DTO.setConstraints(TABLE_5_CONSTRAINTS_DTO); @@ -113,6 +118,7 @@ public abstract class AbstractUnitTest extends BaseTest { TABLE_8_DTO.setConstraints(TABLE_8_CONSTRAINTS_DTO); TABLE_8_PRIVILEGED_DTO.setColumns(new LinkedList<>(TABLE_8_COLUMNS_DTO)); TABLE_8_PRIVILEGED_DTO.setConstraints(TABLE_8_CONSTRAINTS_DTO); + TABLE_8_PRIVILEGED_DTO.setDatabase(DATABASE_3_PRIVILEGED_DTO); VIEW_5.setDatabase(DATABASE_3); VIEW_5.setColumns(VIEW_5_COLUMNS); IDENTIFIER_6.setDatabase(DATABASE_3); diff --git a/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/BaseTest.java b/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/BaseTest.java index 0341a7a5dfad8f3a218dd195631ff956289b6b15..c6c0e4ec10150224ee4c21c6a1bf582649ba941e 100644 --- a/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/BaseTest.java +++ b/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/BaseTest.java @@ -1,12 +1,18 @@ package at.tuwien.test; import at.tuwien.ExportResourceDto; -import at.tuwien.api.amqp.*; +import at.tuwien.api.amqp.CreateVirtualHostDto; +import at.tuwien.api.amqp.ExchangeDto; +import at.tuwien.api.amqp.GrantVirtualHostPermissionsDto; +import at.tuwien.api.amqp.QueueDto; import at.tuwien.api.auth.LoginRequestDto; import at.tuwien.api.auth.SignupRequestDto; import at.tuwien.api.container.ContainerBriefDto; import at.tuwien.api.container.ContainerDto; -import at.tuwien.api.container.image.*; +import at.tuwien.api.container.image.ImageBriefDto; +import at.tuwien.api.container.image.ImageChangeDto; +import at.tuwien.api.container.image.ImageCreateDto; +import at.tuwien.api.container.image.ImageDto; import at.tuwien.api.container.internal.PrivilegedContainerDto; import at.tuwien.api.database.*; import at.tuwien.api.database.internal.CreateDatabaseDto; @@ -20,7 +26,10 @@ import at.tuwien.api.database.table.TableCreateDto; import at.tuwien.api.database.table.TableDto; import at.tuwien.api.database.table.TableStatisticDto; import at.tuwien.api.database.table.columns.*; -import at.tuwien.api.database.table.columns.concepts.*; +import at.tuwien.api.database.table.columns.concepts.ConceptDto; +import at.tuwien.api.database.table.columns.concepts.ConceptSaveDto; +import at.tuwien.api.database.table.columns.concepts.UnitDto; +import at.tuwien.api.database.table.columns.concepts.UnitSaveDto; import at.tuwien.api.database.table.constraints.ConstraintsCreateDto; import at.tuwien.api.database.table.constraints.ConstraintsDto; import at.tuwien.api.database.table.constraints.foreign.*; @@ -51,11 +60,9 @@ import at.tuwien.api.orcid.person.name.OrcidValueDto; import at.tuwien.api.semantics.OntologyCreateDto; import at.tuwien.api.semantics.OntologyModifyDto; import at.tuwien.api.user.*; -import at.tuwien.api.user.UserDetailsDto; import at.tuwien.api.user.internal.UpdateUserPasswordDto; import at.tuwien.entities.container.Container; import at.tuwien.entities.container.image.ContainerImage; -import at.tuwien.entities.container.image.ContainerImageDate; import at.tuwien.entities.database.*; import at.tuwien.entities.database.table.Table; import at.tuwien.entities.database.table.columns.TableColumn; @@ -90,6 +97,8 @@ import java.math.BigInteger; import java.nio.charset.Charset; import java.security.Principal; import java.time.Instant; +import java.time.LocalDate; +import java.time.ZoneOffset; import java.util.*; import java.util.stream.Collectors; @@ -134,7 +143,7 @@ import static java.time.temporal.ChronoUnit.MINUTES; * <li>Identifier 6 (Title=en, Description=en, Query=3)</li> * </ul> * <p> - * Database 4 (Public, User 4) + * Database 4 (Public, User 4) -> Container 4 * <li>Identifier 7 (Database=4)</li> * <ul> * </ul> @@ -380,6 +389,7 @@ public abstract class BaseTest { public final static String USER_BROKER_USERNAME = "guest"; public final static String USER_BROKER_PASSWORD = "guest"; + public final static UUID USER_LOCAL_ADMIN_ID = UUID.fromString("a54dcb2e-a644-4e82-87e7-05a96413983d"); public final static String USER_LOCAL_ADMIN_USERNAME = "admin"; public final static String USER_LOCAL_ADMIN_PASSWORD = "admin"; @@ -419,17 +429,6 @@ public abstract class BaseTest { public final static Instant USER_1_LAST_MODIFIED = USER_1_CREATED; public final static UUID USER_1_REALM_ID = REALM_DBREPO_ID; - public final static CreateUserDto USER_1_RABBITMQ_CREATE_DTO = CreateUserDto.builder() - .password("") - .tags("") - .build(); - - public final static GrantVirtualHostPermissionsDto USER_1_RABBITMQ_GRANT_DTO = GrantVirtualHostPermissionsDto.builder() - .configure("") - .read("") - .write("") - .build(); - public final static UpdateUserPasswordDto USER_1_UPDATE_PASSWORD_DTO = UpdateUserPasswordDto.builder() .username(USER_1_USERNAME) .password(USER_1_PASSWORD) @@ -896,36 +895,14 @@ public abstract class BaseTest { USER_6_PASSWORD, USER_6_DETAILS.getAuthorities()); public final static Long IMAGE_1_ID = 1L; - public final static String IMAGE_1_REGISTRY = "docker.io/library"; + public final static String IMAGE_1_REGISTRY = "docker.io"; public final static String IMAGE_1_NAME = "mariadb"; public final static String IMAGE_1_VERSION = "11.1.3"; public final static String IMAGE_1_DIALECT = "org.hibernate.dialect.MariaDBDialect"; public final static String IMAGE_1_DRIVER = "org.mariadb.jdbc.Driver"; public final static String IMAGE_1_JDBC = "mariadb"; public final static Integer IMAGE_1_PORT = 3306; - - public final static Long IMAGE_DATE_1_ID = 1L; - public final static Long IMAGE_DATE_1_IMAGE_ID = IMAGE_1_ID; - public final static String IMAGE_DATE_1_UNIX_FORMAT = "yyyy-MM-dd"; - public final static String IMAGE_DATE_1_DATABASE_FORMAT = "%Y-%c-%d"; - public final static String IMAGE_DATE_1_EXAMPLE = "2022-01-30"; - public final static Boolean IMAGE_DATE_1_HAS_TIME = false; - - public final static ContainerImageDate IMAGE_DATE_1 = ContainerImageDate.builder() - .id(IMAGE_DATE_1_ID) - .iid(IMAGE_DATE_1_IMAGE_ID) - .unixFormat(IMAGE_DATE_1_UNIX_FORMAT) - .databaseFormat(IMAGE_DATE_1_DATABASE_FORMAT) - .example(IMAGE_DATE_1_EXAMPLE) - .hasTime(IMAGE_DATE_1_HAS_TIME) - .build(); - - public final static ImageDateDto IMAGE_DATE_1_DTO = ImageDateDto.builder() - .id(IMAGE_DATE_1_ID) - .unixFormat(IMAGE_DATE_1_UNIX_FORMAT) - .databaseFormat(IMAGE_DATE_1_DATABASE_FORMAT) - .hasTime(IMAGE_DATE_1_HAS_TIME) - .build(); + public final static Boolean IMAGE_1_IS_DEFAULT = true; public final static ImageCreateDto IMAGE_1_CREATE_DTO = ImageCreateDto.builder() .registry(IMAGE_1_REGISTRY) @@ -945,75 +922,6 @@ public abstract class BaseTest { .defaultPort(IMAGE_1_PORT) .build(); - public final static Long IMAGE_DATE_2_ID = 2L; - public final static Long IMAGE_DATE_2_IMAGE_ID = IMAGE_1_ID; - public final static String IMAGE_DATE_2_UNIX_FORMAT = "dd.MM.yy"; - public final static String IMAGE_DATE_2_DATABASE_FORMAT = "%d.%c.%y"; - public final static String IMAGE_DATE_2_EXAMPLE = "30.01.2022"; - public final static Boolean IMAGE_DATE_2_HAS_TIME = false; - - public final static ContainerImageDate IMAGE_DATE_2 = ContainerImageDate.builder() - .id(IMAGE_DATE_2_ID) - .iid(IMAGE_DATE_2_IMAGE_ID) - .unixFormat(IMAGE_DATE_2_UNIX_FORMAT) - .databaseFormat(IMAGE_DATE_2_DATABASE_FORMAT) - .example(IMAGE_DATE_2_EXAMPLE) - .hasTime(IMAGE_DATE_2_HAS_TIME) - .build(); - - public final static ImageDateDto IMAGE_DATE_2_DTO = ImageDateDto.builder() - .id(IMAGE_DATE_2_ID) - .unixFormat(IMAGE_DATE_2_UNIX_FORMAT) - .databaseFormat(IMAGE_DATE_2_DATABASE_FORMAT) - .hasTime(IMAGE_DATE_2_HAS_TIME) - .build(); - - public final static Long IMAGE_DATE_3_ID = 3L; - public final static Long IMAGE_DATE_3_IMAGE_ID = IMAGE_1_ID; - public final static String IMAGE_DATE_3_UNIX_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSSSS"; - public final static String IMAGE_DATE_3_DATABASE_FORMAT = "%Y-%c-%dT%H:%i:%S.%f"; - public final static String IMAGE_DATE_3_EXAMPLE = "2022-01-30T13:44:25.499"; - public final static Boolean IMAGE_DATE_3_HAS_TIME = true; - - public final static ContainerImageDate IMAGE_DATE_3 = ContainerImageDate.builder() - .id(IMAGE_DATE_3_ID) - .iid(IMAGE_DATE_3_IMAGE_ID) - .unixFormat(IMAGE_DATE_3_UNIX_FORMAT) - .databaseFormat(IMAGE_DATE_3_DATABASE_FORMAT) - .example(IMAGE_DATE_3_EXAMPLE) - .hasTime(IMAGE_DATE_3_HAS_TIME) - .build(); - - public final static ImageDateDto IMAGE_DATE_3_DTO = ImageDateDto.builder() - .id(IMAGE_DATE_3_ID) - .unixFormat(IMAGE_DATE_3_UNIX_FORMAT) - .databaseFormat(IMAGE_DATE_3_DATABASE_FORMAT) - .hasTime(IMAGE_DATE_3_HAS_TIME) - .build(); - - public final static Long IMAGE_DATE_4_ID = 4L; - public final static Long IMAGE_DATE_4_IMAGE_ID = IMAGE_1_ID; - public final static String IMAGE_DATE_4_UNIX_FORMAT = "HH:mm:ss"; - public final static String IMAGE_DATE_4_DATABASE_FORMAT = "%H:%i:%S"; - public final static String IMAGE_DATE_4_EXAMPLE = "14:44:25"; - public final static Boolean IMAGE_DATE_4_HAS_TIME = true; - - public final static ContainerImageDate IMAGE_DATE_4 = ContainerImageDate.builder() - .id(IMAGE_DATE_4_ID) - .iid(IMAGE_DATE_4_IMAGE_ID) - .unixFormat(IMAGE_DATE_4_UNIX_FORMAT) - .databaseFormat(IMAGE_DATE_4_DATABASE_FORMAT) - .example(IMAGE_DATE_4_EXAMPLE) - .hasTime(IMAGE_DATE_4_HAS_TIME) - .build(); - - public final static ImageDateDto IMAGE_DATE_4_DTO = ImageDateDto.builder() - .id(IMAGE_DATE_4_ID) - .unixFormat(IMAGE_DATE_4_UNIX_FORMAT) - .databaseFormat(IMAGE_DATE_4_DATABASE_FORMAT) - .hasTime(IMAGE_DATE_4_HAS_TIME) - .build(); - public final static ContainerImage IMAGE_1 = ContainerImage.builder() .id(IMAGE_1_ID) .name(IMAGE_1_NAME) @@ -1023,7 +931,7 @@ public abstract class BaseTest { .jdbcMethod(IMAGE_1_JDBC) .driverClass(IMAGE_1_DRIVER) .defaultPort(IMAGE_1_PORT) - .dateFormats(new LinkedList<>(List.of(IMAGE_DATE_1, IMAGE_DATE_2, IMAGE_DATE_3, IMAGE_DATE_4))) + .isDefault(IMAGE_1_IS_DEFAULT) .build(); public final static ImageDto IMAGE_1_DTO = ImageDto.builder() @@ -1035,13 +943,14 @@ public abstract class BaseTest { .jdbcMethod(IMAGE_1_JDBC) .driverClass(IMAGE_1_DRIVER) .defaultPort(IMAGE_1_PORT) - .dateFormats(List.of(IMAGE_DATE_1_DTO, IMAGE_DATE_2_DTO, IMAGE_DATE_3_DTO)) + .isDefault(IMAGE_1_IS_DEFAULT) .build(); public final static ImageBriefDto IMAGE_1_BRIEF_DTO = ImageBriefDto.builder() .id(IMAGE_1_ID) .name(IMAGE_1_NAME) .version(IMAGE_1_VERSION) + .isDefault(IMAGE_1_IS_DEFAULT) .build(); public final static Long CONTAINER_1_ID = 1L; @@ -1053,7 +962,8 @@ public abstract class BaseTest { public final static String CONTAINER_1_UI_HOST = "localhost"; public final static Integer CONTAINER_1_UI_PORT = 3306; public final static String CONTAINER_1_UI_ADDITIONAL_FLAGS = "?sslMode=disable"; - public final static Boolean CONTAINER_1_RUNNING = true; + public final static Integer CONTAINER_1_QUOTA = 4; + public final static Integer CONTAINER_1_COUNT = 3; public final static String CONTAINER_1_HOST = "localhost"; public final static Integer CONTAINER_1_PORT = 3308; public final static String CONTAINER_1_SIDECAR_HOST = "localhost"; @@ -1072,6 +982,7 @@ public abstract class BaseTest { .port(CONTAINER_1_PORT) .uiHost(CONTAINER_1_UI_HOST) .uiPort(CONTAINER_1_UI_PORT) + .quota(CONTAINER_1_QUOTA) .uiAdditionalFlags(CONTAINER_1_UI_ADDITIONAL_FLAGS) .privilegedUsername(CONTAINER_1_PRIVILEGED_USERNAME) .privilegedPassword(CONTAINER_1_PRIVILEGED_PASSWORD) @@ -1094,7 +1005,8 @@ public abstract class BaseTest { .name(CONTAINER_1_NAME) .internalName(CONTAINER_1_INTERNALNAME) .created(CONTAINER_1_CREATED) - .running(CONTAINER_1_RUNNING) + .quota(CONTAINER_1_QUOTA) + .count(CONTAINER_1_COUNT) .build(); public final static PrivilegedContainerDto CONTAINER_1_PRIVILEGED_DTO = PrivilegedContainerDto.builder() @@ -1121,7 +1033,8 @@ public abstract class BaseTest { public final static Integer CONTAINER_2_PORT = 3309; public final static String CONTAINER_2_SIDECAR_HOST = "localhost"; public final static Integer CONTAINER_2_SIDECAR_PORT = 33091; - public final static Boolean CONTAINER_2_RUNNING = true; + public final static Integer CONTAINER_2_QUOTA = 3; + public final static Integer CONTAINER_2_COUNT = 3; public final static String CONTAINER_2_PRIVILEGED_USERNAME = "root"; public final static String CONTAINER_2_PRIVILEGED_PASSWORD = "dbrepo"; public final static Instant CONTAINER_2_CREATED = Instant.ofEpochSecond(1677399655L) /* 2023-02-26 08:20:55 (UTC) */; @@ -1134,6 +1047,8 @@ public abstract class BaseTest { .created(CONTAINER_2_CREATED) .host(CONTAINER_2_HOST) .port(CONTAINER_2_PORT) + .quota(CONTAINER_2_QUOTA) + .databases(List.of()) .privilegedUsername(CONTAINER_2_PRIVILEGED_USERNAME) .privilegedPassword(CONTAINER_2_PRIVILEGED_PASSWORD) .build(); @@ -1153,7 +1068,7 @@ public abstract class BaseTest { .name(CONTAINER_2_NAME) .internalName(CONTAINER_2_INTERNALNAME) .created(CONTAINER_2_CREATED) - .running(CONTAINER_2_RUNNING) + .quota(CONTAINER_2_QUOTA) .build(); public final static Long CONTAINER_3_ID = 3L; @@ -1163,6 +1078,7 @@ public abstract class BaseTest { public final static String CONTAINER_3_IP = "172.30.0.7"; public final static String CONTAINER_3_HOST = "localhost"; public final static Integer CONTAINER_3_PORT = 3310; + public final static Integer CONTAINER_3_QUOTA = 20; public final static String CONTAINER_3_SIDECAR_HOST = "localhost"; public final static Integer CONTAINER_3_SIDECAR_PORT = 33101; public final static String CONTAINER_3_PRIVILEGED_USERNAME = "root"; @@ -1177,6 +1093,8 @@ public abstract class BaseTest { .created(CONTAINER_3_CREATED) .host(CONTAINER_3_HOST) .port(CONTAINER_3_PORT) + .quota(CONTAINER_3_QUOTA) + .databases(List.of()) .privilegedUsername(CONTAINER_3_PRIVILEGED_USERNAME) .privilegedPassword(CONTAINER_3_PRIVILEGED_PASSWORD) .build(); @@ -1188,6 +1106,7 @@ public abstract class BaseTest { public final static String CONTAINER_4_IP = "172.30.0.8"; public final static String CONTAINER_4_HOST = "localhost"; public final static Integer CONTAINER_4_PORT = 3311; + public final static Integer CONTAINER_4_QUOTA = 0; public final static String CONTAINER_4_SIDECAR_HOST = "localhost"; public final static Integer CONTAINER_4_SIDECAR_PORT = 33111; public final static String CONTAINER_4_PRIVILEGED_USERNAME = "root"; @@ -1202,6 +1121,7 @@ public abstract class BaseTest { .created(CONTAINER_4_CREATED) .host(CONTAINER_4_HOST) .port(CONTAINER_4_PORT) + .quota(CONTAINER_4_QUOTA) .privilegedUsername(CONTAINER_4_PRIVILEGED_USERNAME) .privilegedPassword(CONTAINER_4_PRIVILEGED_PASSWORD) .build(); @@ -1235,12 +1155,6 @@ public abstract class BaseTest { public final static UserDto DATABASE_1_CREATOR_DTO = USER_1_DTO; public final static UserDto DATABASE_1_OWNER_DTO = USER_1_DTO; - public final static GrantExchangePermissionsDto USER_1_RABBITMQ_GRANT_TOPIC_DTO = GrantExchangePermissionsDto.builder() - .exchange("dbrepo") - .read("^(dbrepo\\." + DATABASE_1_INTERNALNAME + "\\..)$") - .write("^(dbrepo\\." + DATABASE_1_INTERNALNAME + "\\..)$") - .build(); - public final static DatabaseCreateDto DATABASE_1_CREATE = DatabaseCreateDto.builder() .name(DATABASE_1_NAME) .isPublic(DATABASE_1_PUBLIC) @@ -1480,25 +1394,21 @@ public abstract class BaseTest { .name("col25") .type(ColumnTypeDto.DATE) .nullAllowed(true) - .dfid(IMAGE_DATE_1_ID) .build(), ColumnCreateDto.builder() .name("col26") .type(ColumnTypeDto.DATETIME) .nullAllowed(true) - .dfid(IMAGE_DATE_3_ID) .build(), ColumnCreateDto.builder() .name("col27") .type(ColumnTypeDto.TIMESTAMP) .nullAllowed(true) - .dfid(IMAGE_DATE_3_ID) .build(), ColumnCreateDto.builder() .name("col28") .type(ColumnTypeDto.TIME) .nullAllowed(true) - .dfid(IMAGE_DATE_4_ID) .build(), ColumnCreateDto.builder() .name("col29") @@ -1599,9 +1509,8 @@ public abstract class BaseTest { .name("id") .internalName("id") .ordinalPosition(0) - .columnType(ColumnTypeDto.BIGINT) + .columnType(ColumnTypeDto.SERIAL) .isNullAllowed(false) - .autoGenerated(false) .enums(null) .sets(null) .build(), @@ -1614,9 +1523,7 @@ public abstract class BaseTest { .internalName("date") .ordinalPosition(1) .columnType(ColumnTypeDto.DATE) - .dateFormat(IMAGE_DATE_1_DTO) .isNullAllowed(true) - .autoGenerated(false) .enums(null) .sets(null) .build(), @@ -1631,7 +1538,6 @@ public abstract class BaseTest { .columnType(ColumnTypeDto.VARCHAR) .size(255L) .isNullAllowed(true) - .autoGenerated(false) .enums(null) .sets(null) .build(), @@ -1647,7 +1553,6 @@ public abstract class BaseTest { .size(10L) .d(0L) .isNullAllowed(true) - .autoGenerated(false) .enums(null) .sets(null) .build(), @@ -1665,7 +1570,6 @@ public abstract class BaseTest { .concept(CONCEPT_1_DTO) .unit(UNIT_1_DTO) .isNullAllowed(true) - .autoGenerated(false) .enums(null) .sets(null) .build()); @@ -1679,6 +1583,40 @@ public abstract class BaseTest { .owner(USER_1_BRIEF_DTO) .build(); + public final static Long TABLE_1_DATA_COUNT = 3L; + public final static QueryResultDto TABLE_1_DATA_DTO = QueryResultDto.builder() + .headers(new LinkedList<>(List.of(new HashMap<>() {{ + put("id", 0); + put("date", 1); + put("location", 2); + put("mintemp", 3); + put("rainfall", 4); + }}))) + .result(new LinkedList<>(List.of( + new HashMap<>() {{ + put("id", BigInteger.valueOf(1L)); + put("date", LocalDate.of(2008, 12, 1).atStartOfDay().toInstant(ZoneOffset.UTC)); + put("location", "Albury"); + put("mintemp", 13.4); + put("rainfall", 0.6); + }}, + new HashMap<>() {{ + put("id", BigInteger.valueOf(2L)); + put("date", LocalDate.of(2008, 12, 2).atStartOfDay().toInstant(ZoneOffset.UTC)); + put("location", "Albury"); + put("mintemp", 7.4); + put("rainfall", 0); + }}, + new HashMap<>() {{ + put("id", BigInteger.valueOf(3L)); + put("date", LocalDate.of(2008, 12, 3).atStartOfDay().toInstant(ZoneOffset.UTC)); + put("location", "Albury"); + put("mintemp", 12.9); + put("rainfall", 0); + }} + ))) + .build(); + public final static Long TABLE_2_ID = 2L; public final static String TABLE_2_NAME = "Weather Location"; public final static String TABLE_2_INTERNALNAME = "weather_location"; @@ -1846,6 +1784,8 @@ public abstract class BaseTest { .build(); public final static ConstraintsCreateDto TABLE_3_CONSTRAINTS_INVALID_CREATE_DTO = ConstraintsCreateDto.builder() + .checks(new LinkedHashSet<>()) + .primaryKey(new LinkedHashSet<>()) // <<<< .uniques(new LinkedList<>()) .foreignKeys(List.of(ForeignKeyCreateDto.builder() .referencedTable("weather_location") @@ -2132,31 +2072,32 @@ public abstract class BaseTest { .columnType(ColumnTypeDto.TIMESTAMP) .build(); + public final static Long COLUMN_4_1_ID = 44L; + + public final static Long COLUMN_4_2_ID = 45L; + public final static List<TableColumn> TABLE_4_COLUMNS = List.of(TableColumn.builder() - .id(44L) + .id(COLUMN_4_1_ID) .ordinalPosition(0) .table(TABLE_4) .name("Timestamp") .internalName("timestamp") .columnType(TableColumnType.TIMESTAMP) .isNullAllowed(false) - .autoGenerated(false) .build(), TableColumn.builder() - .id(45L) + .id(COLUMN_4_2_ID) .ordinalPosition(1) .table(TABLE_4) .name("Value") .internalName("value") .columnType(TableColumnType.DECIMAL) .isNullAllowed(true) - .autoGenerated(false) .build()); public final static List<ColumnCreateDto> TABLE_4_COLUMNS_CREATE_DTO = List.of(ColumnCreateDto.builder() .name("Timestamp") .type(ColumnTypeDto.TIMESTAMP) - .dfid(IMAGE_DATE_4_ID) .nullAllowed(false) .build(), ColumnCreateDto.builder() @@ -2169,7 +2110,7 @@ public abstract class BaseTest { public final static ConstraintsCreateDto TABLE_4_CONSTRAINTS_CREATE_DTO = ConstraintsCreateDto.builder() .checks(new LinkedHashSet<>()) - .primaryKey(new LinkedHashSet<>()) + .primaryKey(new LinkedHashSet<>(Set.of("Timestamp"))) .foreignKeys(new LinkedList<>()) .uniques(List.of(List.of("Timestamp"))) .build(); @@ -2189,26 +2130,22 @@ public abstract class BaseTest { .build(); public final static List<ColumnDto> TABLE_4_COLUMNS_DTO = List.of(ColumnDto.builder() - .id(44L) + .id(COLUMN_4_1_ID) .databaseId(DATABASE_1_ID) .tableId(TABLE_4_ID) .name("Timestamp") .internalName("timestamp") .columnType(ColumnTypeDto.TIMESTAMP) - .dateFormat(IMAGE_DATE_3_DTO) .isNullAllowed(false) - .autoGenerated(false) .build(), ColumnDto.builder() - .id(45L) + .id(COLUMN_4_2_ID) .databaseId(DATABASE_1_ID) .tableId(TABLE_4_ID) .name("Value") .internalName("value") .columnType(ColumnTypeDto.DECIMAL) - .dateFormat(null) .isNullAllowed(true) - .autoGenerated(false) .build()); public final static Long TABLE_8_ID = 8L; @@ -2402,39 +2339,34 @@ public abstract class BaseTest { .sparqlEndpoint(ONTOLOGY_5_SPARQL_ENDPOINT) .build(); - public final static Long COLUMN_8_1_ID = 72L; + public final static Long COLUMN_8_1_ID = 75L; public final static Integer COLUMN_8_1_ORDINALPOS = 0; - public final static Boolean COLUMN_8_1_PRIMARY = true; public final static String COLUMN_8_1_NAME = "ID"; public final static String COLUMN_8_1_INTERNAL_NAME = "id"; public final static TableColumnType COLUMN_8_1_TYPE = TableColumnType.BIGINT; public final static ColumnTypeDto COLUMN_8_1_TYPE_DTO = ColumnTypeDto.BIGINT; - public final static Long COLUMN_8_1_DATE_FORMAT = null; public final static Boolean COLUMN_8_1_NULL = false; public final static Boolean COLUMN_8_1_AUTO_GENERATED = true; - public final static String COLUMN_8_1_FOREIGN_KEY = null; - public final static String COLUMN_8_1_CHECK = null; - public final static List<String> COLUMN_8_1_ENUM_VALUES = null; - public final static List<String> COLUMN_8_1_ENUM_VALUES_DTO = null; - public final static List<String> COLUMN_8_1_SET_VALUES = null; - public final static List<String> COLUMN_8_1_SET_VALUES_DTO = null; - - public final static Long COLUMN_8_2_ID = 73L; + + public final static Long COLUMN_8_2_ID = 76L; public final static Integer COLUMN_8_2_ORDINALPOS = 1; - public final static Boolean COLUMN_8_2_PRIMARY = true; public final static String COLUMN_8_2_NAME = "Value"; public final static String COLUMN_8_2_INTERNAL_NAME = "value"; - public final static TableColumnType COLUMN_8_2_TYPE = TableColumnType.INT; - public final static ColumnTypeDto COLUMN_8_2_TYPE_DTO = ColumnTypeDto.INT; - public final static Long COLUMN_8_2_DATE_FORMAT = null; - public final static Boolean COLUMN_8_2_NULL = true; + public final static TableColumnType COLUMN_8_2_TYPE = TableColumnType.DECIMAL; + public final static ColumnTypeDto COLUMN_8_2_TYPE_DTO = ColumnTypeDto.DECIMAL; + public final static Long COLUMN_8_2_SIZE = 10L; + public final static Long COLUMN_8_2_D = 10L; + public final static Boolean COLUMN_8_2_NULL = false; public final static Boolean COLUMN_8_2_AUTO_GENERATED = false; - public final static String COLUMN_8_2_FOREIGN_KEY = null; - public final static String COLUMN_8_2_CHECK = null; - public final static List<String> COLUMN_8_2_ENUM_VALUES = null; - public final static List<String> COLUMN_8_2_ENUM_VALUES_DTO = null; - public final static List<String> COLUMN_8_2_SET_VALUES = null; - public final static List<String> COLUMN_8_2_SET_VALUES_DTO = null; + + public final static Long COLUMN_8_3_ID = 77L; + public final static Integer COLUMN_8_3_ORDINALPOS = 2; + public final static String COLUMN_8_3_NAME = "raw"; + public final static String COLUMN_8_3_INTERNAL_NAME = "raw"; + public final static TableColumnType COLUMN_8_3_TYPE = TableColumnType.LONGBLOB; + public final static ColumnTypeDto COLUMN_8_3_TYPE_DTO = ColumnTypeDto.LONGBLOB; + public final static Boolean COLUMN_8_3_NULL = true; + public final static Boolean COLUMN_8_3_AUTO_GENERATED = false; public final static ColumnBriefDto TABLE_8_COLUMNS_BRIEF_0_DTO = ColumnBriefDto.builder() .id(COLUMN_8_1_ID) @@ -2451,7 +2383,6 @@ public abstract class BaseTest { .internalName(COLUMN_8_1_INTERNAL_NAME) .columnType(COLUMN_8_1_TYPE) .isNullAllowed(COLUMN_8_1_NULL) - .autoGenerated(COLUMN_8_1_AUTO_GENERATED) .build(), TableColumn.builder() .id(COLUMN_8_2_ID) @@ -2461,7 +2392,17 @@ public abstract class BaseTest { .internalName(COLUMN_8_2_INTERNAL_NAME) .columnType(COLUMN_8_2_TYPE) .isNullAllowed(COLUMN_8_2_NULL) - .autoGenerated(COLUMN_8_2_AUTO_GENERATED) + .size(COLUMN_8_2_SIZE) + .d(COLUMN_8_2_D) + .build(), + TableColumn.builder() + .id(COLUMN_8_3_ID) + .ordinalPosition(COLUMN_8_3_ORDINALPOS) + .table(TABLE_8) + .name(COLUMN_8_3_NAME) + .internalName(COLUMN_8_3_INTERNAL_NAME) + .columnType(COLUMN_8_3_TYPE) + .isNullAllowed(COLUMN_8_3_NULL) .build()); public final static List<ColumnDto> TABLE_8_COLUMNS_DTO = List.of(ColumnDto.builder() @@ -2472,7 +2413,6 @@ public abstract class BaseTest { .internalName(COLUMN_8_1_INTERNAL_NAME) .columnType(COLUMN_8_1_TYPE_DTO) .isNullAllowed(COLUMN_8_1_NULL) - .autoGenerated(COLUMN_8_1_AUTO_GENERATED) .build(), ColumnDto.builder() .id(COLUMN_8_2_ID) @@ -2482,7 +2422,15 @@ public abstract class BaseTest { .internalName(COLUMN_8_2_INTERNAL_NAME) .columnType(COLUMN_8_2_TYPE_DTO) .isNullAllowed(COLUMN_8_2_NULL) - .autoGenerated(COLUMN_8_2_AUTO_GENERATED) + .build(), + ColumnDto.builder() + .id(COLUMN_8_3_ID) + .ordinalPosition(COLUMN_8_3_ORDINALPOS) + .table(TABLE_8_DTO) + .name(COLUMN_8_3_NAME) + .internalName(COLUMN_8_3_INTERNAL_NAME) + .columnType(COLUMN_8_3_TYPE_DTO) + .isNullAllowed(COLUMN_8_3_NULL) .build()); public final static Long TABLE_8_DATA_COUNT = 6L; @@ -2492,12 +2440,36 @@ public abstract class BaseTest { put(COLUMN_8_2_INTERNAL_NAME, 1); }}))) .result(new LinkedList<>(List.of( - Map.of(COLUMN_8_1_INTERNAL_NAME, BigInteger.valueOf(1L), COLUMN_8_2_INTERNAL_NAME, 11.2), - Map.of(COLUMN_8_1_INTERNAL_NAME, BigInteger.valueOf(2L), COLUMN_8_2_INTERNAL_NAME, 11.3), - Map.of(COLUMN_8_1_INTERNAL_NAME, BigInteger.valueOf(3L), COLUMN_8_2_INTERNAL_NAME, 11.4), - Map.of(COLUMN_8_1_INTERNAL_NAME, BigInteger.valueOf(4L), COLUMN_8_2_INTERNAL_NAME, 11.9), - Map.of(COLUMN_8_1_INTERNAL_NAME, BigInteger.valueOf(5L), COLUMN_8_2_INTERNAL_NAME, 12.3), - Map.of(COLUMN_8_1_INTERNAL_NAME, BigInteger.valueOf(6L), COLUMN_8_2_INTERNAL_NAME, 23.1) + new HashMap<>() {{ + put(COLUMN_8_1_INTERNAL_NAME, BigInteger.valueOf(1L)); + put(COLUMN_8_2_INTERNAL_NAME, 11.2); + put(COLUMN_8_3_INTERNAL_NAME, null); + }}, + new HashMap<>() {{ + put(COLUMN_8_1_INTERNAL_NAME, BigInteger.valueOf(2L)); + put(COLUMN_8_2_INTERNAL_NAME, 11.3); + put(COLUMN_8_3_INTERNAL_NAME, null); + }}, + new HashMap<>() {{ + put(COLUMN_8_1_INTERNAL_NAME, BigInteger.valueOf(3L)); + put(COLUMN_8_2_INTERNAL_NAME, 11.4); + put(COLUMN_8_3_INTERNAL_NAME, null); + }}, + new HashMap<>() {{ + put(COLUMN_8_1_INTERNAL_NAME, BigInteger.valueOf(4L)); + put(COLUMN_8_2_INTERNAL_NAME, 11.9); + put(COLUMN_8_3_INTERNAL_NAME, null); + }}, + new HashMap<>() {{ + put(COLUMN_8_1_INTERNAL_NAME, BigInteger.valueOf(5L)); + put(COLUMN_8_2_INTERNAL_NAME, 12.3); + put(COLUMN_8_3_INTERNAL_NAME, null); + }}, + new HashMap<>() {{ + put(COLUMN_8_1_INTERNAL_NAME, BigInteger.valueOf(6L)); + put(COLUMN_8_2_INTERNAL_NAME, 23.1); + put(COLUMN_8_3_INTERNAL_NAME, null); + }} ))) .build(); @@ -2558,8 +2530,6 @@ public abstract class BaseTest { public final static Long QUERY_2_ID = 2L; public final static String QUERY_2_STATEMENT = "SELECT `location` FROM `weather_aus`"; public final static String QUERY_2_QUERY_HASH = "a2d2dd94ebc7653bb5a3b55dd8ed5e91d3d13c225c6855a1eb4eb7ca14c36ced"; - public final static Long QUERY_2_CONTAINER_ID = CONTAINER_2_ID; - public final static Long QUERY_2_DATABASE_ID = DATABASE_2_ID; public final static Long QUERY_2_RESULT_NUMBER = 2L; public final static String QUERY_2_RESULT_HASH = "ff3f7cbe1b96d296957f6e39e55b8b1b577fa3d205d4795af99594cfd20cb80d"; public final static Instant QUERY_2_CREATED = Instant.now().minus(2, MINUTES); @@ -2571,7 +2541,7 @@ public abstract class BaseTest { public final static QueryDto QUERY_2_DTO = QueryDto.builder() .id(QUERY_2_ID) - .databaseId(QUERY_2_DATABASE_ID) + .databaseId(DATABASE_2_ID) .query(QUERY_2_STATEMENT) .queryNormalized(QUERY_2_STATEMENT) .resultNumber(QUERY_2_RESULT_NUMBER) @@ -2737,8 +2707,6 @@ public abstract class BaseTest { public final static Long QUERY_6_ID = 6L; public final static String QUERY_6_STATEMENT = "SELECT `location` FROM `weather_aus` WHERE `id` = 1"; public final static String QUERY_6_QUERY_HASH = "6d6dc48b12cdfd959d39a62887334a6bbd529b93eed4f211f3f671bd9e7d6225"; - public final static Long QUERY_6_CONTAINER_ID = CONTAINER_2_ID; - public final static Long QUERY_6_DATABASE_ID = DATABASE_2_ID; public final static String QUERY_6_RESULT_HASH = "ff5f7cbe1b96d596957f6e59e55b8b1b577fa5d505d5795af99595cfd50cb80d"; public final static Instant QUERY_6_CREATED = Instant.now().minus(5, MINUTES); public final static Instant QUERY_6_EXECUTION = Instant.now().minus(1, MINUTES); @@ -2750,7 +2718,7 @@ public abstract class BaseTest { public final static QueryDto QUERY_6_DTO = QueryDto.builder() .id(QUERY_6_ID) - .databaseId(QUERY_6_DATABASE_ID) + .databaseId(DATABASE_2_ID) .query(QUERY_6_STATEMENT) .queryNormalized(QUERY_6_STATEMENT) .resultNumber(QUERY_6_RESULT_NUMBER) @@ -2771,29 +2739,36 @@ public abstract class BaseTest { .columnType(ColumnTypeDto.BIGINT) .build(); + public final static Long COLUMN_1_1_ID = 1L; + + public final static Long COLUMN_1_2_ID = 2L; + + public final static Long COLUMN_1_3_ID = 3L; + + public final static Long COLUMN_1_4_ID = 4L; + + public final static Long COLUMN_1_5_ID = 5L; + public final static List<TableColumn> TABLE_1_COLUMNS = List.of(TableColumn.builder() - .id(1L) + .id(COLUMN_1_1_ID) .ordinalPosition(0) .table(TABLE_1) .name("id") .internalName("id") - .columnType(TableColumnType.BIGINT) + .columnType(TableColumnType.SERIAL) .isNullAllowed(false) - .autoGenerated(false) .build(), TableColumn.builder() - .id(2L) + .id(COLUMN_1_2_ID) .ordinalPosition(1) .table(TABLE_1) .name("Date") .internalName("date") .columnType(TableColumnType.DATE) - .dateFormat(IMAGE_DATE_1) .isNullAllowed(true) - .autoGenerated(false) .build(), TableColumn.builder() - .id(3L) + .id(COLUMN_1_3_ID) .ordinalPosition(2) .table(TABLE_1) .name("Location") @@ -2801,10 +2776,9 @@ public abstract class BaseTest { .columnType(TableColumnType.VARCHAR) .size(255L) .isNullAllowed(true) - .autoGenerated(false) .build(), TableColumn.builder() - .id(4L) + .id(COLUMN_1_4_ID) .ordinalPosition(3) .table(TABLE_1) .name("MinTemp") @@ -2813,10 +2787,9 @@ public abstract class BaseTest { .size(10L) .d(0L) .isNullAllowed(true) - .autoGenerated(false) .build(), TableColumn.builder() - .id(5L) + .id(COLUMN_1_5_ID) .ordinalPosition(4) .table(TABLE_1) .name("Rainfall") @@ -2827,7 +2800,6 @@ public abstract class BaseTest { .concept(CONCEPT_1) .unit(UNIT_1) .isNullAllowed(true) - .autoGenerated(false) .build()); public final static List<ColumnCreateDto> TABLE_1_COLUMNS_CREATE_DTO = List.of(ColumnCreateDto.builder() @@ -2841,14 +2813,12 @@ public abstract class BaseTest { .name("Date") .type(ColumnTypeDto.DATE) .nullAllowed(true) - .dfid(IMAGE_DATE_1_ID) .build(), ColumnCreateDto.builder() .name("Location") .type(ColumnTypeDto.VARCHAR) .size(255L) .nullAllowed(true) - .dfid(IMAGE_DATE_1_ID) .build(), ColumnCreateDto.builder() .name("MinTemp") @@ -2856,7 +2826,6 @@ public abstract class BaseTest { .size(10L) .d(0L) .nullAllowed(true) - .dfid(IMAGE_DATE_1_ID) .build(), ColumnCreateDto.builder() .name("Rainfall") @@ -2864,7 +2833,6 @@ public abstract class BaseTest { .size(10L) .d(0L) .nullAllowed(true) - .dfid(IMAGE_DATE_1_ID) .conceptUri(CONCEPT_1_URI) .unitUri(UNIT_1_URI) .build()); @@ -2876,6 +2844,13 @@ public abstract class BaseTest { .uniques(List.of(List.of("date"))) .build(); + public final static ConstraintsCreateDto TABLE_1_CONSTRAINTS_CREATE_INVALID_DTO = ConstraintsCreateDto.builder() + .checks(new LinkedHashSet<>()) + .primaryKey(new LinkedHashSet<>()) + .foreignKeys(new LinkedList<>()) + .uniques(List.of(List.of("date"))) + .build(); + public final static TableCreateDto TABLE_1_CREATE_DTO = TableCreateDto.builder() .name(TABLE_1_NAME) .description(TABLE_1_DESCRIPTION) @@ -2890,8 +2865,21 @@ public abstract class BaseTest { .constraints(TABLE_1_CONSTRAINTS_CREATE_DTO) .build(); + public final static at.tuwien.api.database.table.internal.TableCreateDto TABLE_1_CREATE_INTERNAL_INVALID_DTO = at.tuwien.api.database.table.internal.TableCreateDto.builder() + .name(TABLE_1_NAME) + .description(TABLE_1_DESCRIPTION) + .columns(TABLE_1_COLUMNS_CREATE_DTO) + .constraints(TABLE_1_CONSTRAINTS_CREATE_INVALID_DTO) + .build(); + + public final static Long COLUMN_2_1_ID = 6L; + + public final static Long COLUMN_2_2_ID = 7L; + + public final static Long COLUMN_2_3_ID = 8L; + public final static List<TableColumn> TABLE_2_COLUMNS = List.of(TableColumn.builder() - .id(6L) + .id(COLUMN_2_1_ID) .ordinalPosition(0) .table(TABLE_2) .name("location") @@ -2900,12 +2888,11 @@ public abstract class BaseTest { .columnType(TableColumnType.VARCHAR) .size(255L) .isNullAllowed(false) - .autoGenerated(false) .enums(null) .sets(null) .build(), TableColumn.builder() - .id(7L) + .id(COLUMN_2_2_ID) .ordinalPosition(1) .table(TABLE_2) .name("lat") @@ -2915,12 +2902,11 @@ public abstract class BaseTest { .size(10L) .d(0L) .isNullAllowed(true) - .autoGenerated(false) .enums(null) .sets(null) .build(), TableColumn.builder() - .id(8L) + .id(COLUMN_2_3_ID) .ordinalPosition(2) .table(TABLE_2) .name("lng") @@ -2930,27 +2916,26 @@ public abstract class BaseTest { .size(10L) .d(0L) .isNullAllowed(true) - .autoGenerated(false) .enums(null) .sets(null) .build()); public final static ColumnBriefDto TABLE_2_COLUMNS_BRIEF_0_DTO = ColumnBriefDto.builder() - .id(6L) + .id(COLUMN_2_1_ID) .name("location") .internalName("location") .columnType(ColumnTypeDto.VARCHAR) .build(); public final static ColumnBriefDto TABLE_2_COLUMNS_BRIEF_2_DTO = ColumnBriefDto.builder() - .id(8L) + .id(COLUMN_2_3_ID) .name("lng") .internalName("lng") .columnType(ColumnTypeDto.DECIMAL) .build(); public final static List<ColumnDto> TABLE_2_COLUMNS_DTO = List.of(ColumnDto.builder() - .id(6L) + .id(COLUMN_2_1_ID) .table(TABLE_2_DTO) .tableId(TABLE_2_ID) .databaseId(DATABASE_1_ID) @@ -2960,12 +2945,11 @@ public abstract class BaseTest { .columnType(ColumnTypeDto.VARCHAR) .size(255L) .isNullAllowed(false) - .autoGenerated(false) .enums(null) .sets(null) .build(), ColumnDto.builder() - .id(7L) + .id(COLUMN_2_2_ID) .table(TABLE_2_DTO) .tableId(TABLE_2_ID) .databaseId(DATABASE_1_ID) @@ -2975,12 +2959,11 @@ public abstract class BaseTest { .columnType(ColumnTypeDto.DOUBLE) .size(22L) .isNullAllowed(true) - .autoGenerated(false) .enums(null) .sets(null) .build(), ColumnDto.builder() - .id(8L) + .id(COLUMN_2_3_ID) .table(TABLE_2_DTO) .tableId(TABLE_2_ID) .databaseId(DATABASE_1_ID) @@ -2990,62 +2973,124 @@ public abstract class BaseTest { .columnType(ColumnTypeDto.DOUBLE) .size(22L) .isNullAllowed(true) - .autoGenerated(false) .enums(null) .sets(null) .build()); + public final static Long COLUMN_3_1_ID = 9L; + + public final static Long COLUMN_3_2_ID = 10L; + + public final static Long COLUMN_3_3_ID = 11L; + + public final static Long COLUMN_3_4_ID = 12L; + + public final static Long COLUMN_3_5_ID = 13L; + + public final static Long COLUMN_3_6_ID = 14L; + + public final static Long COLUMN_3_7_ID = 15L; + + public final static Long COLUMN_3_8_ID = 16L; + + public final static Long COLUMN_3_9_ID = 17L; + + public final static Long COLUMN_3_10_ID = 18L; + + public final static Long COLUMN_3_11_ID = 19L; + + public final static Long COLUMN_3_12_ID = 20L; + + public final static Long COLUMN_3_13_ID = 21L; + + public final static Long COLUMN_3_14_ID = 22L; + + public final static Long COLUMN_3_15_ID = 23L; + + public final static Long COLUMN_3_16_ID = 24L; + + public final static Long COLUMN_3_17_ID = 25L; + + public final static Long COLUMN_3_18_ID = 26L; + + public final static Long COLUMN_3_19_ID = 27L; + + public final static Long COLUMN_3_20_ID = 28L; + + public final static Long COLUMN_3_21_ID = 29L; + + public final static Long COLUMN_3_22_ID = 30L; + + public final static Long COLUMN_3_23_ID = 31L; + + public final static Long COLUMN_3_24_ID = 32L; + + public final static Long COLUMN_3_25_ID = 33L; + + public final static Long COLUMN_3_26_ID = 34L; + + public final static Long COLUMN_3_27_ID = 35L; + + public final static Long COLUMN_3_28_ID = 36L; + + public final static Long COLUMN_3_29_ID = 37L; + + public final static Long COLUMN_3_30_ID = 38L; + + public final static Long COLUMN_3_31_ID = 39L; + + public final static Long COLUMN_3_32_ID = 40L; + + public final static Long COLUMN_3_33_ID = 41L; + + public final static Long COLUMN_3_34_ID = 42L; + + public final static Long COLUMN_3_35_ID = 43L; + public final static ColumnBriefDto TABLE_3_COLUMNS_BRIEF_0_DTO = ColumnBriefDto.builder() - .id(9L) + .id(COLUMN_3_1_ID) .columnType(ColumnTypeDto.BIGINT) .name("id") .internalName("id") .build(); public final static List<TableColumn> TABLE_3_COLUMNS = List.of(TableColumn.builder() - .id(9L) + .id(COLUMN_3_1_ID) .table(TABLE_3) .ordinalPosition(0) - .autoGenerated(true) .columnType(TableColumnType.BIGINT) .name("id") .internalName("id") .isNullAllowed(false) - .dateFormat(null) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), TableColumn.builder() - .id(10L) + .id(COLUMN_3_2_ID) .table(TABLE_3) .ordinalPosition(1) - .autoGenerated(false) .columnType(TableColumnType.INT) .name("linie") .internalName("linie") .isNullAllowed(true) - .dateFormat(null) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), TableColumn.builder() - .id(11L) + .id(COLUMN_3_3_ID) .table(TABLE_3) .ordinalPosition(2) - .autoGenerated(false) .columnType(TableColumnType.INT) .name("richtung") .internalName("richtung") .isNullAllowed(true) - .dateFormat(null) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), TableColumn.builder() - .id(12L) + .id(COLUMN_3_4_ID) .table(TABLE_3) .ordinalPosition(3) - .autoGenerated(false) .columnType(TableColumnType.DATE) .name("betriebsdatum") .internalName("betriebsdatum") @@ -3054,88 +3099,75 @@ public abstract class BaseTest { .sets(new LinkedList<>()) .build(), TableColumn.builder() - .id(13L) + .id(COLUMN_3_5_ID) .table(TABLE_3) .ordinalPosition(4) - .autoGenerated(false) .columnType(TableColumnType.INT) .name("fahrzeug") .internalName("fahrzeug") .isNullAllowed(true) - .dateFormat(null) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), TableColumn.builder() - .id(14L) + .id(COLUMN_3_6_ID) .table(TABLE_3) .ordinalPosition(5) - .autoGenerated(false) .columnType(TableColumnType.INT) .name("kurs") .internalName("kurs") .isNullAllowed(true) - .dateFormat(null) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), TableColumn.builder() - .id(15L) + .id(COLUMN_3_7_ID) .table(TABLE_3) .ordinalPosition(6) - .autoGenerated(false) .columnType(TableColumnType.INT) .name("seq_von") .internalName("seq_von") .isNullAllowed(true) - .dateFormat(null) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), TableColumn.builder() - .id(16L) + .id(COLUMN_3_8_ID) .table(TABLE_3) .ordinalPosition(7) - .autoGenerated(false) .columnType(TableColumnType.INT) .name("halt_diva_von") .internalName("halt_diva_von") .isNullAllowed(true) - .dateFormat(null) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), TableColumn.builder() - .id(17L) + .id(COLUMN_3_9_ID) .table(TABLE_3) .ordinalPosition(8) - .autoGenerated(false) .columnType(TableColumnType.INT) .name("halt_punkt_diva_von") .internalName("halt_punkt_diva_von") .isNullAllowed(true) - .dateFormat(null) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), TableColumn.builder() - .id(18L) + .id(COLUMN_3_10_ID) .table(TABLE_3) .ordinalPosition(9) - .autoGenerated(false) .columnType(TableColumnType.INT) .name("halt_kurz_von1") .internalName("halt_kurz_von1") .isNullAllowed(true) - .dateFormat(null) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), TableColumn.builder() - .id(19L) + .id(COLUMN_3_11_ID) .table(TABLE_3) .ordinalPosition(10) - .autoGenerated(false) .columnType(TableColumnType.DATE) .name("datum_von") .internalName("datum_von") @@ -3144,114 +3176,97 @@ public abstract class BaseTest { .sets(new LinkedList<>()) .build(), TableColumn.builder() - .id(20L) + .id(COLUMN_3_12_ID) .table(TABLE_3) .ordinalPosition(11) - .autoGenerated(false) .columnType(TableColumnType.INT) .name("soll_an_von") .internalName("soll_an_von") .isNullAllowed(true) - .dateFormat(null) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), TableColumn.builder() - .id(21L) + .id(COLUMN_3_13_ID) .table(TABLE_3) .ordinalPosition(12) - .autoGenerated(false) .columnType(TableColumnType.INT) .name("ist_an_von") .internalName("ist_an_von") .isNullAllowed(true) - .dateFormat(null) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), TableColumn.builder() - .id(22L) + .id(COLUMN_3_14_ID) .table(TABLE_3) .ordinalPosition(13) - .autoGenerated(false) .columnType(TableColumnType.INT) .name("soll_ab_von") .internalName("soll_ab_von") .isNullAllowed(true) - .dateFormat(null) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), TableColumn.builder() - .id(23L) + .id(COLUMN_3_15_ID) .table(TABLE_3) .ordinalPosition(14) - .autoGenerated(false) .columnType(TableColumnType.INT) .name("ist_ab_von") .internalName("ist_ab_von") .isNullAllowed(true) - .dateFormat(null) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), TableColumn.builder() - .id(24L) + .id(COLUMN_3_16_ID) .table(TABLE_3) .ordinalPosition(15) - .autoGenerated(false) .columnType(TableColumnType.INT) .name("seq_nach") .internalName("seq_nach") .isNullAllowed(true) - .dateFormat(null) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), TableColumn.builder() - .id(25L) + .id(COLUMN_3_17_ID) .table(TABLE_3) .ordinalPosition(16) - .autoGenerated(false) .columnType(TableColumnType.INT) .name("halt_diva_nach") .internalName("halt_diva_nach") .isNullAllowed(true) - .dateFormat(null) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), TableColumn.builder() - .id(26L) + .id(COLUMN_3_18_ID) .table(TABLE_3) .ordinalPosition(17) - .autoGenerated(false) .columnType(TableColumnType.INT) .name("halt_punkt_diva_nach") .internalName("halt_punkt_diva_nach") .isNullAllowed(true) - .dateFormat(null) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), TableColumn.builder() - .id(27L) + .id(COLUMN_3_19_ID) .table(TABLE_3) .ordinalPosition(18) - .autoGenerated(false) .columnType(TableColumnType.INT) .name("halt_kurz_nach1") .internalName("halt_kurz_nach1") .isNullAllowed(true) - .dateFormat(null) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), TableColumn.builder() - .id(28L) + .id(COLUMN_3_20_ID) .table(TABLE_3) .ordinalPosition(19) - .autoGenerated(false) .columnType(TableColumnType.DATE) .name("datum_nach") .internalName("datum_nach") @@ -3260,912 +3275,833 @@ public abstract class BaseTest { .sets(new LinkedList<>()) .build(), TableColumn.builder() - .id(29L) + .id(COLUMN_3_21_ID) .table(TABLE_3) .ordinalPosition(20) - .autoGenerated(false) .columnType(TableColumnType.INT) .name("soll_an_nach") .internalName("soll_an_nach") .isNullAllowed(true) - .dateFormat(null) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), TableColumn.builder() - .id(30L) + .id(COLUMN_3_22_ID) .table(TABLE_3) .ordinalPosition(21) - .autoGenerated(false) .columnType(TableColumnType.INT) .name("ist_an_nach1") .internalName("ist_an_nach1") .isNullAllowed(true) - .dateFormat(null) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), TableColumn.builder() - .id(31L) + .id(COLUMN_3_23_ID) .table(TABLE_3) .ordinalPosition(22) - .autoGenerated(false) .columnType(TableColumnType.INT) .name("soll_ab_nach") .internalName("soll_ab_nach") .isNullAllowed(true) - .dateFormat(null) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), TableColumn.builder() - .id(32L) + .id(COLUMN_3_24_ID) .table(TABLE_3) .ordinalPosition(23) - .autoGenerated(false) .columnType(TableColumnType.INT) .name("ist_ab_nach") .internalName("ist_ab_nach") .isNullAllowed(true) - .dateFormat(null) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), TableColumn.builder() - .id(33L) + .id(COLUMN_3_25_ID) .table(TABLE_3) .ordinalPosition(24) - .autoGenerated(false) .columnType(TableColumnType.INT) .name("fahrt_id") .internalName("fahrt_id") .isNullAllowed(true) - .dateFormat(null) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), TableColumn.builder() - .id(34L) + .id(COLUMN_3_26_ID) .table(TABLE_3) .ordinalPosition(25) - .autoGenerated(false) .columnType(TableColumnType.INT) .name("fahrweg_id") .internalName("fahrweg_id") .isNullAllowed(true) - .dateFormat(null) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), TableColumn.builder() - .id(35L) + .id(COLUMN_3_27_ID) .table(TABLE_3) .ordinalPosition(26) - .autoGenerated(false) .columnType(TableColumnType.INT) .name("fw_no") .internalName("fw_no") .isNullAllowed(true) - .dateFormat(null) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), TableColumn.builder() - .id(36L) + .id(COLUMN_3_28_ID) .table(TABLE_3) .ordinalPosition(27) - .autoGenerated(false) .columnType(TableColumnType.INT) .name("fw_typ") .internalName("fw_typ") .isNullAllowed(true) - .dateFormat(null) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), TableColumn.builder() - .id(37L) + .id(COLUMN_3_29_ID) .table(TABLE_3) .ordinalPosition(28) - .autoGenerated(false) .columnType(TableColumnType.INT) .name("fw_kurz") .internalName("fw_kurz") .isNullAllowed(true) - .dateFormat(null) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), TableColumn.builder() - .id(38L) + .id(COLUMN_3_30_ID) .table(TABLE_3) .ordinalPosition(29) - .autoGenerated(false) .columnType(TableColumnType.INT) .name("fw_lang") .internalName("fw_lang") .isNullAllowed(true) - .dateFormat(null) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), TableColumn.builder() - .id(39L) + .id(COLUMN_3_31_ID) .table(TABLE_3) .ordinalPosition(30) - .autoGenerated(false) .columnType(TableColumnType.INT) .name("umlauf_von") .internalName("umlauf_von") .isNullAllowed(true) - .dateFormat(null) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), TableColumn.builder() - .id(40L) + .id(COLUMN_3_32_ID) .table(TABLE_3) .ordinalPosition(31) - .autoGenerated(false) .columnType(TableColumnType.INT) .name("halt_id_von") .internalName("halt_id_von") .isNullAllowed(true) - .dateFormat(null) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), TableColumn.builder() - .id(41L) + .id(COLUMN_3_33_ID) .table(TABLE_3) .ordinalPosition(32) - .autoGenerated(false) .columnType(TableColumnType.INT) .name("halt_id_nach") .internalName("halt_id_nach") .isNullAllowed(true) - .dateFormat(null) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), TableColumn.builder() - .id(42L) + .id(COLUMN_3_34_ID) .table(TABLE_3) .ordinalPosition(33) - .autoGenerated(false) .columnType(TableColumnType.INT) .name("halt_punkt_id_von") .internalName("halt_punkt_id_von") .isNullAllowed(true) - .dateFormat(null) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), TableColumn.builder() - .id(43L) + .id(COLUMN_3_35_ID) .table(TABLE_3) .ordinalPosition(34) - .autoGenerated(false) .columnType(TableColumnType.INT) .name("halt_punkt_id_nach") .internalName("halt_punkt_id_nach") .isNullAllowed(true) - .dateFormat(null) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build()); public final static List<ColumnDto> TABLE_3_COLUMNS_DTO = List.of(ColumnDto.builder() - .id(9L) + .id(COLUMN_3_1_ID) .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(true) .columnType(ColumnTypeDto.BIGINT) .name("id") .internalName("id") .isNullAllowed(false) - .dateFormat(null) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), ColumnDto.builder() - .id(10L) + .id(COLUMN_3_2_ID) .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.INT) .name("linie") .internalName("linie") .isNullAllowed(true) - .dateFormat(null) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), ColumnDto.builder() - .id(11L) + .id(COLUMN_3_3_ID) .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.INT) .name("richtung") .internalName("richtung") .isNullAllowed(true) - .dateFormat(null) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), ColumnDto.builder() - .id(12L) + .id(COLUMN_3_4_ID) .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.DATE) .name("betriebsdatum") .internalName("betriebsdatum") .isNullAllowed(true) - .dateFormat(IMAGE_DATE_2_DTO) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), ColumnDto.builder() - .id(13L) + .id(COLUMN_3_5_ID) .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.INT) .name("fahrzeug") .internalName("fahrzeug") .isNullAllowed(true) - .dateFormat(null) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), ColumnDto.builder() - .id(14L) + .id(COLUMN_3_6_ID) .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.INT) .name("kurs") .internalName("kurs") .isNullAllowed(true) - .dateFormat(null) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), ColumnDto.builder() - .id(15L) + .id(COLUMN_3_7_ID) .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.INT) .name("seq_von") .internalName("seq_von") .isNullAllowed(true) - .dateFormat(null) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), ColumnDto.builder() - .id(16L) + .id(COLUMN_3_8_ID) .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.INT) .name("halt_diva_von") .internalName("halt_diva_von") .isNullAllowed(true) - .dateFormat(null) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), ColumnDto.builder() - .id(17L) + .id(COLUMN_3_9_ID) .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.INT) .name("halt_punkt_diva_von") .internalName("halt_punkt_diva_von") .isNullAllowed(true) - .dateFormat(null) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), ColumnDto.builder() - .id(18L) + .id(COLUMN_3_10_ID) .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.INT) .name("halt_kurz_von1") .internalName("halt_kurz_von1") .isNullAllowed(true) - .dateFormat(null) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), ColumnDto.builder() - .id(19L) + .id(COLUMN_3_11_ID) .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.DATE) .name("datum_von") .internalName("datum_von") .isNullAllowed(true) - .dateFormat(IMAGE_DATE_2_DTO) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), ColumnDto.builder() - .id(20L) + .id(COLUMN_3_12_ID) .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.INT) .name("soll_an_von") .internalName("soll_an_von") .isNullAllowed(true) - .dateFormat(null) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), ColumnDto.builder() - .id(21L) + .id(COLUMN_3_13_ID) .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.INT) .name("ist_an_von") .internalName("ist_an_von") .isNullAllowed(true) - .dateFormat(null) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), ColumnDto.builder() - .id(22L) + .id(COLUMN_3_14_ID) .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.INT) .name("soll_ab_von") .internalName("soll_ab_von") .isNullAllowed(true) - .dateFormat(null) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), ColumnDto.builder() - .id(23L) + .id(COLUMN_3_15_ID) .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.INT) .name("ist_ab_von") .internalName("ist_ab_von") .isNullAllowed(true) - .dateFormat(null) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), ColumnDto.builder() - .id(24L) + .id(COLUMN_3_16_ID) .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.INT) .name("seq_nach") .internalName("seq_nach") .isNullAllowed(true) - .dateFormat(null) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), ColumnDto.builder() - .id(25L) + .id(COLUMN_3_17_ID) .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.INT) .name("halt_diva_nach") .internalName("halt_diva_nach") .isNullAllowed(true) - .dateFormat(null) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), ColumnDto.builder() - .id(26L) + .id(COLUMN_3_18_ID) .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.INT) .name("halt_punkt_diva_nach") .internalName("halt_punkt_diva_nach") .isNullAllowed(true) - .dateFormat(null) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), ColumnDto.builder() - .id(27L) + .id(COLUMN_3_19_ID) .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.INT) .name("halt_kurz_nach1") .internalName("halt_kurz_nach1") .isNullAllowed(true) - .dateFormat(null) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), ColumnDto.builder() - .id(28L) + .id(COLUMN_3_20_ID) .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.DATE) .name("datum_nach") .internalName("datum_nach") .isNullAllowed(true) - .dateFormat(IMAGE_DATE_2_DTO) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), ColumnDto.builder() - .id(29L) + .id(COLUMN_3_21_ID) .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.INT) .name("soll_an_nach") .internalName("soll_an_nach") .isNullAllowed(true) - .dateFormat(null) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), ColumnDto.builder() - .id(30L) + .id(COLUMN_3_22_ID) .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.INT) .name("ist_an_nach1") .internalName("ist_an_nach1") .isNullAllowed(true) - .dateFormat(null) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), ColumnDto.builder() - .id(31L) + .id(COLUMN_3_23_ID) .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.INT) .name("soll_ab_nach") .internalName("soll_ab_nach") .isNullAllowed(true) - .dateFormat(null) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), ColumnDto.builder() - .id(32L) + .id(COLUMN_3_24_ID) .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.INT) .name("ist_ab_nach") .internalName("ist_ab_nach") .isNullAllowed(true) - .dateFormat(null) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), ColumnDto.builder() - .id(33L) + .id(COLUMN_3_25_ID) .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.INT) .name("fahrt_id") .internalName("fahrt_id") .isNullAllowed(true) - .dateFormat(null) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), ColumnDto.builder() - .id(34L) + .id(COLUMN_3_26_ID) .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.INT) .name("fahrweg_id") .internalName("fahrweg_id") .isNullAllowed(true) - .dateFormat(null) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), ColumnDto.builder() - .id(35L) + .id(COLUMN_3_27_ID) .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.INT) .name("fw_no") .internalName("fw_no") .isNullAllowed(true) - .dateFormat(null) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), ColumnDto.builder() - .id(36L) + .id(COLUMN_3_28_ID) .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.INT) .name("fw_typ") .internalName("fw_typ") .isNullAllowed(true) - .dateFormat(null) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), ColumnDto.builder() - .id(37L) + .id(COLUMN_3_29_ID) .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.INT) .name("fw_kurz") .internalName("fw_kurz") .isNullAllowed(true) - .dateFormat(null) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), ColumnDto.builder() - .id(38L) + .id(COLUMN_3_30_ID) .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.INT) .name("fw_lang") .internalName("fw_lang") .isNullAllowed(true) - .dateFormat(null) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), ColumnDto.builder() - .id(39L) + .id(COLUMN_3_31_ID) .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.INT) .name("umlauf_von") .internalName("umlauf_von") .isNullAllowed(true) - .dateFormat(null) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), ColumnDto.builder() - .id(40L) + .id(COLUMN_3_32_ID) .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.INT) .name("halt_id_von") .internalName("halt_id_von") .isNullAllowed(true) - .dateFormat(null) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), ColumnDto.builder() - .id(41L) + .id(COLUMN_3_33_ID) .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.INT) .name("halt_id_nach") .internalName("halt_id_nach") .isNullAllowed(true) - .dateFormat(null) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), ColumnDto.builder() - .id(42L) + .id(COLUMN_3_34_ID) .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.INT) .name("halt_punkt_id_von") .internalName("halt_punkt_id_von") .isNullAllowed(true) - .dateFormat(null) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build(), ColumnDto.builder() - .id(43L) + .id(COLUMN_3_35_ID) .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.INT) .name("halt_punkt_id_nach") .internalName("halt_punkt_id_nach") .isNullAllowed(true) - .dateFormat(null) .enums(new LinkedList<>()) .sets(new LinkedList<>()) .build()); + public final static Long COLUMN_5_1_ID = 46L; + + public final static Long COLUMN_5_2_ID = 47L; + + public final static Long COLUMN_5_3_ID = 48L; + + public final static Long COLUMN_5_4_ID = 49L; + + public final static Long COLUMN_5_5_ID = 50L; + + public final static Long COLUMN_5_6_ID = 51L; + + public final static Long COLUMN_5_7_ID = 52L; + + public final static Long COLUMN_5_8_ID = 53L; + + public final static Long COLUMN_5_9_ID = 54L; + + public final static Long COLUMN_5_10_ID = 55L; + + public final static Long COLUMN_5_11_ID = 56L; + + public final static Long COLUMN_5_12_ID = 57L; + + public final static Long COLUMN_5_13_ID = 58L; + + public final static Long COLUMN_5_14_ID = 59L; + + public final static Long COLUMN_5_15_ID = 60L; + + public final static Long COLUMN_5_16_ID = 61L; + + public final static Long COLUMN_5_17_ID = 62L; + + public final static Long COLUMN_5_18_ID = 63L; + + public final static Long COLUMN_5_19_ID = 64L; + + public final static Long COLUMN_5_20_ID = 65L; + + public final static Long COLUMN_5_21_ID = 66L; + public final static ColumnBriefDto TABLE_5_COLUMNS_BRIEF_0_DTO = ColumnBriefDto.builder() - .id(45L) + .id(COLUMN_5_1_ID) .name("id") .internalName("id") .columnType(ColumnTypeDto.BIGINT) .build(); public final static List<TableColumn> TABLE_5_COLUMNS = List.of(TableColumn.builder() - .id(45L) + .id(COLUMN_5_1_ID) .ordinalPosition(0) .table(TABLE_5) .name("id") .internalName("id") .columnType(TableColumnType.BIGINT) .isNullAllowed(false) - .autoGenerated(true) .build(), TableColumn.builder() - .id(46L) + .id(COLUMN_5_2_ID) .ordinalPosition(1) .table(TABLE_5) .name("Animal Name") .internalName("animal_name") .columnType(TableColumnType.VARCHAR) .isNullAllowed(true) - .autoGenerated(false) .build(), TableColumn.builder() - .id(47L) + .id(COLUMN_5_3_ID) .ordinalPosition(2) .table(TABLE_5) .name("Hair") .internalName("hair") .columnType(TableColumnType.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), TableColumn.builder() - .id(48L) + .id(COLUMN_5_4_ID) .ordinalPosition(3) .table(TABLE_5) .name("Feathers") .internalName("feathers") .columnType(TableColumnType.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), TableColumn.builder() - .id(49L) + .id(COLUMN_5_5_ID) .ordinalPosition(4) .table(TABLE_5) .name("Bread") .internalName("bread") .columnType(TableColumnType.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), TableColumn.builder() - .id(50L) + .id(COLUMN_5_6_ID) .ordinalPosition(5) .table(TABLE_5) .name("Eggs") .internalName("eggs") .columnType(TableColumnType.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), TableColumn.builder() - .id(51L) + .id(COLUMN_5_7_ID) .ordinalPosition(6) .table(TABLE_5) .name("Milk") .internalName("milk") .columnType(TableColumnType.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), TableColumn.builder() - .id(52L) + .id(COLUMN_5_8_ID) .ordinalPosition(7) .table(TABLE_5) .name("Water") .internalName("water") .columnType(TableColumnType.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), TableColumn.builder() - .id(53L) + .id(COLUMN_5_9_ID) .ordinalPosition(8) .table(TABLE_5) .name("Airborne") .internalName("airborne") .columnType(TableColumnType.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), TableColumn.builder() - .id(54L) + .id(COLUMN_5_10_ID) .ordinalPosition(9) .table(TABLE_5) .name("Waterborne") .internalName("waterborne") .columnType(TableColumnType.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), TableColumn.builder() - .id(55L) + .id(COLUMN_5_11_ID) .ordinalPosition(10) .table(TABLE_5) .name("Aquantic") .internalName("aquantic") .columnType(TableColumnType.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), TableColumn.builder() - .id(56L) + .id(COLUMN_5_12_ID) .ordinalPosition(11) .table(TABLE_5) .name("Predator") .internalName("predator") .columnType(TableColumnType.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), TableColumn.builder() - .id(57L) + .id(COLUMN_5_13_ID) .ordinalPosition(12) .table(TABLE_5) .name("Backbone") .internalName("backbone") .columnType(TableColumnType.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), TableColumn.builder() - .id(58L) + .id(COLUMN_5_14_ID) .ordinalPosition(13) .table(TABLE_5) .name("Breathes") .internalName("breathes") .columnType(TableColumnType.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), TableColumn.builder() - .id(59L) + .id(COLUMN_5_15_ID) .ordinalPosition(14) .table(TABLE_5) .name("Venomous") .internalName("venomous") .columnType(TableColumnType.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), TableColumn.builder() - .id(60L) + .id(COLUMN_5_16_ID) .ordinalPosition(15) .table(TABLE_5) .name("Fin") .internalName("fin") .columnType(TableColumnType.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), TableColumn.builder() - .id(61L) + .id(COLUMN_5_17_ID) .ordinalPosition(16) .table(TABLE_5) .name("Legs") .internalName("legs") .columnType(TableColumnType.INT) .isNullAllowed(true) - .autoGenerated(false) .build(), TableColumn.builder() - .id(62L) + .id(COLUMN_5_18_ID) .ordinalPosition(17) .table(TABLE_5) .name("Tail") .internalName("tail") .columnType(TableColumnType.DECIMAL) .isNullAllowed(true) - .autoGenerated(false) .build(), TableColumn.builder() - .id(63L) + .id(COLUMN_5_19_ID) .ordinalPosition(18) .table(TABLE_5) .name("Domestic") .internalName("domestic") .columnType(TableColumnType.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), TableColumn.builder() - .id(64L) + .id(COLUMN_5_20_ID) .ordinalPosition(19) .table(TABLE_5) .name("Catsize") .internalName("catsize") .columnType(TableColumnType.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), TableColumn.builder() - .id(65L) + .id(COLUMN_5_21_ID) .ordinalPosition(20) .table(TABLE_5) .name("Class Type") .internalName("class_type") .columnType(TableColumnType.DECIMAL) .isNullAllowed(true) - .autoGenerated(false) .build()); public final static List<ColumnDto> TABLE_5_COLUMNS_DTO = List.of(ColumnDto.builder() - .id(45L) + .id(COLUMN_5_1_ID) .ordinalPosition(0) .tableId(TABLE_5_ID) .table(TABLE_5_DTO) @@ -4173,10 +4109,9 @@ public abstract class BaseTest { .internalName("id") .columnType(ColumnTypeDto.BIGINT) .isNullAllowed(false) - .autoGenerated(true) .build(), ColumnDto.builder() - .id(46L) + .id(COLUMN_5_2_ID) .ordinalPosition(1) .tableId(TABLE_5_ID) .table(TABLE_5_DTO) @@ -4184,10 +4119,9 @@ public abstract class BaseTest { .internalName("animal_name") .columnType(ColumnTypeDto.VARCHAR) .isNullAllowed(true) - .autoGenerated(false) .build(), ColumnDto.builder() - .id(47L) + .id(COLUMN_5_3_ID) .ordinalPosition(2) .tableId(TABLE_5_ID) .table(TABLE_5_DTO) @@ -4195,10 +4129,9 @@ public abstract class BaseTest { .internalName("hair") .columnType(ColumnTypeDto.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), ColumnDto.builder() - .id(48L) + .id(COLUMN_5_4_ID) .ordinalPosition(3) .tableId(TABLE_5_ID) .table(TABLE_5_DTO) @@ -4206,10 +4139,9 @@ public abstract class BaseTest { .internalName("feathers") .columnType(ColumnTypeDto.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), ColumnDto.builder() - .id(49L) + .id(COLUMN_5_5_ID) .ordinalPosition(4) .tableId(TABLE_5_ID) .table(TABLE_5_DTO) @@ -4217,10 +4149,9 @@ public abstract class BaseTest { .internalName("bread") .columnType(ColumnTypeDto.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), ColumnDto.builder() - .id(50L) + .id(COLUMN_5_6_ID) .ordinalPosition(5) .tableId(TABLE_5_ID) .table(TABLE_5_DTO) @@ -4228,10 +4159,9 @@ public abstract class BaseTest { .internalName("eggs") .columnType(ColumnTypeDto.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), ColumnDto.builder() - .id(51L) + .id(COLUMN_5_7_ID) .ordinalPosition(6) .tableId(TABLE_5_ID) .table(TABLE_5_DTO) @@ -4239,10 +4169,9 @@ public abstract class BaseTest { .internalName("milk") .columnType(ColumnTypeDto.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), ColumnDto.builder() - .id(52L) + .id(COLUMN_5_8_ID) .ordinalPosition(7) .tableId(TABLE_5_ID) .table(TABLE_5_DTO) @@ -4250,10 +4179,9 @@ public abstract class BaseTest { .internalName("water") .columnType(ColumnTypeDto.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), ColumnDto.builder() - .id(53L) + .id(COLUMN_5_9_ID) .ordinalPosition(8) .tableId(TABLE_5_ID) .table(TABLE_5_DTO) @@ -4261,10 +4189,9 @@ public abstract class BaseTest { .internalName("airborne") .columnType(ColumnTypeDto.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), ColumnDto.builder() - .id(54L) + .id(COLUMN_5_10_ID) .ordinalPosition(9) .tableId(TABLE_5_ID) .table(TABLE_5_DTO) @@ -4272,10 +4199,9 @@ public abstract class BaseTest { .internalName("waterborne") .columnType(ColumnTypeDto.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), ColumnDto.builder() - .id(55L) + .id(COLUMN_5_11_ID) .ordinalPosition(10) .tableId(TABLE_5_ID) .table(TABLE_5_DTO) @@ -4283,10 +4209,9 @@ public abstract class BaseTest { .internalName("aquantic") .columnType(ColumnTypeDto.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), ColumnDto.builder() - .id(56L) + .id(COLUMN_5_12_ID) .ordinalPosition(11) .tableId(TABLE_5_ID) .table(TABLE_5_DTO) @@ -4294,10 +4219,9 @@ public abstract class BaseTest { .internalName("predator") .columnType(ColumnTypeDto.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), ColumnDto.builder() - .id(57L) + .id(COLUMN_5_13_ID) .ordinalPosition(12) .tableId(TABLE_5_ID) .table(TABLE_5_DTO) @@ -4305,10 +4229,9 @@ public abstract class BaseTest { .internalName("backbone") .columnType(ColumnTypeDto.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), ColumnDto.builder() - .id(58L) + .id(COLUMN_5_14_ID) .ordinalPosition(13) .tableId(TABLE_5_ID) .table(TABLE_5_DTO) @@ -4316,10 +4239,9 @@ public abstract class BaseTest { .internalName("breathes") .columnType(ColumnTypeDto.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), ColumnDto.builder() - .id(59L) + .id(COLUMN_5_15_ID) .ordinalPosition(14) .tableId(TABLE_5_ID) .table(TABLE_5_DTO) @@ -4327,10 +4249,9 @@ public abstract class BaseTest { .internalName("venomous") .columnType(ColumnTypeDto.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), ColumnDto.builder() - .id(60L) + .id(COLUMN_5_16_ID) .ordinalPosition(15) .tableId(TABLE_5_ID) .table(TABLE_5_DTO) @@ -4338,10 +4259,9 @@ public abstract class BaseTest { .internalName("fin") .columnType(ColumnTypeDto.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), ColumnDto.builder() - .id(61L) + .id(COLUMN_5_17_ID) .ordinalPosition(16) .tableId(TABLE_5_ID) .table(TABLE_5_DTO) @@ -4349,10 +4269,9 @@ public abstract class BaseTest { .internalName("legs") .columnType(ColumnTypeDto.INT) .isNullAllowed(true) - .autoGenerated(false) .build(), ColumnDto.builder() - .id(62L) + .id(COLUMN_5_18_ID) .ordinalPosition(17) .tableId(TABLE_5_ID) .table(TABLE_5_DTO) @@ -4360,10 +4279,9 @@ public abstract class BaseTest { .internalName("tail") .columnType(ColumnTypeDto.DECIMAL) .isNullAllowed(true) - .autoGenerated(false) .build(), ColumnDto.builder() - .id(63L) + .id(COLUMN_5_19_ID) .ordinalPosition(18) .tableId(TABLE_5_ID) .table(TABLE_5_DTO) @@ -4371,10 +4289,9 @@ public abstract class BaseTest { .internalName("domestic") .columnType(ColumnTypeDto.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), ColumnDto.builder() - .id(64L) + .id(COLUMN_5_20_ID) .ordinalPosition(19) .tableId(TABLE_5_ID) .table(TABLE_5_DTO) @@ -4382,10 +4299,9 @@ public abstract class BaseTest { .internalName("catsize") .columnType(ColumnTypeDto.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), ColumnDto.builder() - .id(65L) + .id(COLUMN_5_21_ID) .ordinalPosition(20) .tableId(TABLE_5_ID) .table(TABLE_5_DTO) @@ -4393,7 +4309,6 @@ public abstract class BaseTest { .internalName("class_type") .columnType(ColumnTypeDto.DECIMAL) .isNullAllowed(true) - .autoGenerated(false) .build()); public final static List<ForeignKeyCreateDto> TABLE_5_FOREIGN_KEYS_INVALID_CREATE = List.of(ForeignKeyCreateDto.builder() @@ -4541,7 +4456,6 @@ public abstract class BaseTest { .internalName("id") .columnType(TableColumnType.BIGINT) .isNullAllowed(false) - .autoGenerated(true) .build(), TableColumn.builder() .id(68L) @@ -4551,7 +4465,6 @@ public abstract class BaseTest { .internalName("firstname") .columnType(TableColumnType.VARCHAR) .isNullAllowed(false) - .autoGenerated(false) .build(), TableColumn.builder() .id(69L) @@ -4561,7 +4474,6 @@ public abstract class BaseTest { .internalName("lastname") .columnType(TableColumnType.VARCHAR) .isNullAllowed(false) - .autoGenerated(false) .build(), TableColumn.builder() .id(70L) @@ -4571,7 +4483,6 @@ public abstract class BaseTest { .internalName("birth") .columnType(TableColumnType.YEAR) .isNullAllowed(false) - .autoGenerated(false) .build(), TableColumn.builder() .id(71L) @@ -4580,9 +4491,7 @@ public abstract class BaseTest { .name("reminder") .internalName("reminder") .columnType(TableColumnType.TIME) - .dateFormat(IMAGE_DATE_4) .isNullAllowed(false) - .autoGenerated(false) .build(), TableColumn.builder() .id(72L) @@ -4592,11 +4501,10 @@ public abstract class BaseTest { .internalName("ref_id") .columnType(TableColumnType.BIGINT) .isNullAllowed(true) - .autoGenerated(false) .build()); public final static ColumnBriefDto TABLE_6_COLUMNS_BRIEF_0_DTO = ColumnBriefDto.builder() - .id(66L) + .id(67L) .name("id") .internalName("id") .columnType(ColumnTypeDto.BIGINT) @@ -4611,7 +4519,6 @@ public abstract class BaseTest { .internalName("id") .columnType(ColumnTypeDto.BIGINT) .isNullAllowed(false) - .autoGenerated(true) .build(), ColumnDto.builder() .id(68L) @@ -4622,7 +4529,6 @@ public abstract class BaseTest { .internalName("firstname") .columnType(ColumnTypeDto.VARCHAR) .isNullAllowed(false) - .autoGenerated(false) .build(), ColumnDto.builder() .id(69L) @@ -4633,7 +4539,6 @@ public abstract class BaseTest { .internalName("lastname") .columnType(ColumnTypeDto.VARCHAR) .isNullAllowed(false) - .autoGenerated(false) .build(), ColumnDto.builder() .id(70L) @@ -4644,7 +4549,6 @@ public abstract class BaseTest { .internalName("birth") .columnType(ColumnTypeDto.YEAR) .isNullAllowed(false) - .autoGenerated(false) .build(), ColumnDto.builder() .id(71L) @@ -4654,9 +4558,7 @@ public abstract class BaseTest { .name("reminder") .internalName("reminder") .columnType(ColumnTypeDto.TIME) - .dateFormat(IMAGE_DATE_4_DTO) .isNullAllowed(false) - .autoGenerated(false) .build(), ColumnDto.builder() .id(72L) @@ -4667,7 +4569,6 @@ public abstract class BaseTest { .internalName("ref_id") .columnType(ColumnTypeDto.BIGINT) .isNullAllowed(true) - .autoGenerated(false) .build()); public final static List<List<String>> TABLE_6_UNIQUES_CREATE = List.of( @@ -4708,43 +4609,45 @@ public abstract class BaseTest { .constraints(TABLE_6_CONSTRAINTS_CREATE) .build(); + public final static Long COLUMN_7_1_ID = 73L; + + public final static Long COLUMN_7_2_ID = 74L; + public final static ColumnBriefDto TABLE_7_COLUMNS_BRIEF_0_DTO = ColumnBriefDto.builder() - .id(26L) + .id(COLUMN_7_1_ID) .name("name_id") .internalName("name_id") .columnType(ColumnTypeDto.BIGINT) .build(); public final static ColumnBriefDto TABLE_7_COLUMNS_BRIEF_1_DTO = ColumnBriefDto.builder() - .id(27L) + .id(COLUMN_7_2_ID) .name("zoo_id") .internalName("zoo_id") .columnType(ColumnTypeDto.BIGINT) .build(); public final static List<TableColumn> TABLE_7_COLUMNS = List.of(TableColumn.builder() - .id(74L) + .id(COLUMN_7_1_ID) .ordinalPosition(0) .table(TABLE_7) .name("name_id") .internalName("name_id") .columnType(TableColumnType.BIGINT) .isNullAllowed(false) - .autoGenerated(false) .build(), TableColumn.builder() - .id(75L) + .id(COLUMN_7_2_ID) .ordinalPosition(1) .table(TABLE_7) .name("zoo_id") .internalName("zoo_id") .columnType(TableColumnType.BIGINT) .isNullAllowed(false) - .autoGenerated(false) .build()); public final static List<ColumnDto> TABLE_7_COLUMNS_DTO = List.of(ColumnDto.builder() - .id(74L) + .id(COLUMN_7_1_ID) .ordinalPosition(0) .tableId(TABLE_7_ID) .table(TABLE_7_DTO) @@ -4752,10 +4655,9 @@ public abstract class BaseTest { .internalName("name_id") .columnType(ColumnTypeDto.BIGINT) .isNullAllowed(false) - .autoGenerated(false) .build(), ColumnDto.builder() - .id(75L) + .id(COLUMN_7_2_ID) .ordinalPosition(1) .tableId(TABLE_7_ID) .table(TABLE_7_DTO) @@ -4763,7 +4665,6 @@ public abstract class BaseTest { .internalName("zoo_id") .columnType(ColumnTypeDto.BIGINT) .isNullAllowed(false) - .autoGenerated(false) .build()); public final static Long VIEW_1_ID = 1L; @@ -4786,7 +4687,6 @@ public abstract class BaseTest { .columnType(ColumnTypeDto.VARCHAR) .size(255L) .isNullAllowed(false) - .autoGenerated(false) .build(), ViewColumnDto.builder() .id(2L) @@ -4797,7 +4697,6 @@ public abstract class BaseTest { .columnType(ColumnTypeDto.DOUBLE) .size(22L) .isNullAllowed(true) - .autoGenerated(false) .build(), ViewColumnDto.builder() .id(3L) @@ -4808,9 +4707,7 @@ public abstract class BaseTest { .columnType(ColumnTypeDto.DOUBLE) .size(22L) .isNullAllowed(true) - .autoGenerated(false) - .build() - ); + .build()); public final static View VIEW_1 = View.builder() .id(VIEW_1_ID) @@ -4861,7 +4758,6 @@ public abstract class BaseTest { .columnType(TableColumnType.VARCHAR) .size(255L) .isNullAllowed(false) - .autoGenerated(false) .view(VIEW_1) .build(), ViewColumn.builder() @@ -4874,7 +4770,6 @@ public abstract class BaseTest { .size(10L) .d(0L) .isNullAllowed(true) - .autoGenerated(false) .view(VIEW_1) .build(), ViewColumn.builder() @@ -4887,7 +4782,6 @@ public abstract class BaseTest { .size(10L) .d(0L) .isNullAllowed(true) - .autoGenerated(false) .view(VIEW_1) .build() ); @@ -4955,20 +4849,16 @@ public abstract class BaseTest { .internalName("date") .ordinalPosition(1) .columnType(ColumnTypeDto.DATE) - .dateFormat(IMAGE_DATE_1_DTO) .isNullAllowed(true) - .autoGenerated(false) .build(), ViewColumnDto.builder() .id(5L) .name("loc") .internalName("loc") - .alias("loc") .ordinalPosition(2) .columnType(ColumnTypeDto.VARCHAR) .size(255L) .isNullAllowed(true) - .autoGenerated(false) .build(), ViewColumnDto.builder() .id(6L) @@ -4979,7 +4869,6 @@ public abstract class BaseTest { .size(10L) .d(0L) .isNullAllowed(true) - .autoGenerated(false) .build(), ViewColumnDto.builder() .id(7L) @@ -4990,7 +4879,6 @@ public abstract class BaseTest { .size(10L) .d(0L) .isNullAllowed(true) - .autoGenerated(false) .build() ); @@ -5014,20 +4902,17 @@ public abstract class BaseTest { .name("Date") .internalName("date") .columnType(TableColumnType.DATE) - .dateFormat(IMAGE_DATE_1) .isNullAllowed(true) - .autoGenerated(false) .view(VIEW_2) .build(), ViewColumn.builder() .id(5L) .ordinalPosition(1) - .name("Location") - .internalName("location") + .name("loc") + .internalName("loc") .columnType(TableColumnType.VARCHAR) .size(255L) .isNullAllowed(true) - .autoGenerated(false) .view(VIEW_2) .build(), ViewColumn.builder() @@ -5039,7 +4924,6 @@ public abstract class BaseTest { .size(10L) .d(0L) .isNullAllowed(true) - .autoGenerated(false) .view(VIEW_2) .build(), ViewColumn.builder() @@ -5051,7 +4935,6 @@ public abstract class BaseTest { .size(10L) .d(0L) .isNullAllowed(true) - .autoGenerated(false) .view(VIEW_2) .build() ); @@ -5105,6 +4988,8 @@ public abstract class BaseTest { public final static String VIEW_3_QUERY = "select w.`mintemp`, w.`rainfall`, w.`location`, m.`date` from `weather_aus` w join `junit2` m on m.`location` = w.`location` and m.`date` = w.`date`"; public final static String VIEW_3_QUERY_HASH = "bbbaa56a5206b3dc3e6cf9301b0db9344eb6f19b100c7b88550ffb597a0bd255"; + public final static Long VIEW_3_DATA_COUNT = 3L; + public final static List<ViewColumnDto> VIEW_3_COLUMNS_DTO = List.of( ViewColumnDto.builder() .id(8L) @@ -5115,7 +5000,6 @@ public abstract class BaseTest { .size(10L) .d(0L) .isNullAllowed(true) - .autoGenerated(false) .build(), ViewColumnDto.builder() .id(9L) @@ -5128,7 +5012,6 @@ public abstract class BaseTest { .concept(CONCEPT_1_DTO) .unit(UNIT_1_DTO) .isNullAllowed(true) - .autoGenerated(false) .build(), ViewColumnDto.builder() .id(10L) @@ -5138,7 +5021,6 @@ public abstract class BaseTest { .columnType(ColumnTypeDto.VARCHAR) .size(255L) .isNullAllowed(true) - .autoGenerated(false) .build(), ViewColumnDto.builder() .id(11L) @@ -5146,9 +5028,7 @@ public abstract class BaseTest { .internalName("date") .ordinalPosition(3) .columnType(ColumnTypeDto.DATE) - .dateFormat(IMAGE_DATE_1_DTO) .isNullAllowed(true) - .autoGenerated(false) .build() ); @@ -5189,7 +5069,6 @@ public abstract class BaseTest { .size(10L) .d(0L) .isNullAllowed(true) - .autoGenerated(false) .view(VIEW_3) .build(), ViewColumn.builder() @@ -5201,7 +5080,6 @@ public abstract class BaseTest { .size(10L) .d(0L) .isNullAllowed(true) - .autoGenerated(false) .view(VIEW_3) .build(), ViewColumn.builder() @@ -5212,7 +5090,6 @@ public abstract class BaseTest { .columnType(TableColumnType.VARCHAR) .size(255L) .isNullAllowed(true) - .autoGenerated(false) .view(VIEW_3) .build(), ViewColumn.builder() @@ -5221,9 +5098,7 @@ public abstract class BaseTest { .name("Date") .internalName("date") .columnType(TableColumnType.DATE) - .dateFormat(IMAGE_DATE_1) .isNullAllowed(true) - .autoGenerated(false) .view(VIEW_3) .build() ); @@ -5273,7 +5148,6 @@ public abstract class BaseTest { .internalName("animal_name") .columnType(ColumnTypeDto.VARCHAR) .isNullAllowed(true) - .autoGenerated(false) .build(), ViewColumnDto.builder() .id(13L) @@ -5282,7 +5156,6 @@ public abstract class BaseTest { .internalName("hair") .columnType(ColumnTypeDto.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), ViewColumnDto.builder() .id(14L) @@ -5291,7 +5164,6 @@ public abstract class BaseTest { .internalName("feathers") .columnType(ColumnTypeDto.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), ViewColumnDto.builder() .id(15L) @@ -5300,7 +5172,6 @@ public abstract class BaseTest { .internalName("eggs") .columnType(ColumnTypeDto.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), ViewColumnDto.builder() .id(16L) @@ -5309,7 +5180,6 @@ public abstract class BaseTest { .internalName("milk") .columnType(ColumnTypeDto.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), ViewColumnDto.builder() .id(17L) @@ -5318,7 +5188,6 @@ public abstract class BaseTest { .internalName("airborne") .columnType(ColumnTypeDto.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), ViewColumnDto.builder() .id(18L) @@ -5327,7 +5196,6 @@ public abstract class BaseTest { .internalName("aquantic") .columnType(ColumnTypeDto.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), ViewColumnDto.builder() .id(19L) @@ -5336,7 +5204,6 @@ public abstract class BaseTest { .internalName("predator") .columnType(ColumnTypeDto.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), ViewColumnDto.builder() .id(20L) @@ -5345,7 +5212,6 @@ public abstract class BaseTest { .internalName("backbone") .columnType(ColumnTypeDto.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), ViewColumnDto.builder() .id(21L) @@ -5354,7 +5220,6 @@ public abstract class BaseTest { .internalName("breathes") .columnType(ColumnTypeDto.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), ViewColumnDto.builder() .id(22L) @@ -5363,7 +5228,6 @@ public abstract class BaseTest { .internalName("venomous") .columnType(ColumnTypeDto.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), ViewColumnDto.builder() .id(23L) @@ -5372,7 +5236,6 @@ public abstract class BaseTest { .internalName("fin") .columnType(ColumnTypeDto.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), ViewColumnDto.builder() .id(24L) @@ -5381,7 +5244,6 @@ public abstract class BaseTest { .internalName("legs") .columnType(ColumnTypeDto.INT) .isNullAllowed(true) - .autoGenerated(false) .build(), ViewColumnDto.builder() .id(25L) @@ -5390,7 +5252,6 @@ public abstract class BaseTest { .internalName("tail") .columnType(ColumnTypeDto.DECIMAL) .isNullAllowed(true) - .autoGenerated(false) .build(), ViewColumnDto.builder() .id(26L) @@ -5399,7 +5260,6 @@ public abstract class BaseTest { .internalName("domestic") .columnType(ColumnTypeDto.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), ViewColumnDto.builder() .id(27L) @@ -5408,7 +5268,6 @@ public abstract class BaseTest { .internalName("catsize") .columnType(ColumnTypeDto.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), ViewColumnDto.builder() .id(28L) @@ -5417,7 +5276,6 @@ public abstract class BaseTest { .internalName("class_type") .columnType(ColumnTypeDto.DECIMAL) .isNullAllowed(true) - .autoGenerated(false) .build()); public final static View VIEW_4 = View.builder() @@ -5446,6 +5304,161 @@ public abstract class BaseTest { .columns(VIEW_4_COLUMNS_DTO) .build(); + public final static List<ViewColumn> VIEW_4_COLUMNS = List.of( + ViewColumn.builder() + .id(12L) + .ordinalPosition(0) + .name("Animal Name") + .internalName("animal_name") + .columnType(TableColumnType.VARCHAR) + .isNullAllowed(true) + .view(VIEW_4) + .build(), + ViewColumn.builder() + .id(13L) + .ordinalPosition(1) + .name("Hair") + .internalName("hair") + .columnType(TableColumnType.BOOL) + .isNullAllowed(true) + .view(VIEW_4) + .build(), + ViewColumn.builder() + .id(14L) + .ordinalPosition(2) + .name("Feathers") + .internalName("feathers") + .columnType(TableColumnType.BOOL) + .isNullAllowed(true) + .view(VIEW_4) + .build(), + ViewColumn.builder() + .id(15L) + .ordinalPosition(3) + .name("Eggs") + .internalName("eggs") + .columnType(TableColumnType.BOOL) + .isNullAllowed(true) + .view(VIEW_4) + .build(), + ViewColumn.builder() + .id(16L) + .ordinalPosition(4) + .name("Milk") + .internalName("milk") + .columnType(TableColumnType.BOOL) + .isNullAllowed(true) + .view(VIEW_4) + .build(), + ViewColumn.builder() + .id(17L) + .ordinalPosition(5) + .name("Airborne") + .internalName("airborne") + .columnType(TableColumnType.BOOL) + .isNullAllowed(true) + .view(VIEW_4) + .build(), + ViewColumn.builder() + .id(18L) + .ordinalPosition(6) + .name("Aquantic") + .internalName("aquantic") + .columnType(TableColumnType.BOOL) + .isNullAllowed(true) + .view(VIEW_4) + .build(), + ViewColumn.builder() + .id(19L) + .ordinalPosition(7) + .name("Predator") + .internalName("predator") + .columnType(TableColumnType.BOOL) + .isNullAllowed(true) + .view(VIEW_4) + .build(), + ViewColumn.builder() + .id(20L) + .ordinalPosition(8) + .name("Backbone") + .internalName("backbone") + .columnType(TableColumnType.BOOL) + .isNullAllowed(true) + .view(VIEW_4) + .build(), + ViewColumn.builder() + .id(21L) + .ordinalPosition(9) + .name("Breathes") + .internalName("breathes") + .columnType(TableColumnType.BOOL) + .isNullAllowed(true) + .view(VIEW_4) + .build(), + ViewColumn.builder() + .id(22L) + .ordinalPosition(10) + .name("Venomous") + .internalName("venomous") + .columnType(TableColumnType.BOOL) + .isNullAllowed(true) + .view(VIEW_4) + .build(), + ViewColumn.builder() + .id(23L) + .ordinalPosition(11) + .name("Fin") + .internalName("fin") + .columnType(TableColumnType.BOOL) + .isNullAllowed(true) + .view(VIEW_4) + .build(), + ViewColumn.builder() + .id(24L) + .ordinalPosition(12) + .name("Legs") + .internalName("legs") + .columnType(TableColumnType.INT) + .isNullAllowed(true) + .view(VIEW_4) + .build(), + ViewColumn.builder() + .id(25L) + .ordinalPosition(13) + .name("Tail") + .internalName("tail") + .columnType(TableColumnType.DECIMAL) + .isNullAllowed(true) + .view(VIEW_4) + .build(), + ViewColumn.builder() + .id(26L) + .ordinalPosition(14) + .name("Domestic") + .internalName("domestic") + .columnType(TableColumnType.BOOL) + .isNullAllowed(true) + .view(VIEW_4) + .build(), + ViewColumn.builder() + .id(27L) + .ordinalPosition(15) + .name("Catsize") + .internalName("catsize") + .columnType(TableColumnType.BOOL) + .isNullAllowed(true) + .view(VIEW_4) + .build(), + ViewColumn.builder() + .id(28L) + .ordinalPosition(16) + .name("Class Type") + .internalName("class_type") + .columnType(TableColumnType.DECIMAL) + .isNullAllowed(true) + .view(VIEW_4) + .build()); + public final static Long VIEW_5_ID = 5L; public final static Boolean VIEW_5_INITIAL_VIEW = false; public final static String VIEW_5_NAME = "Mock View"; @@ -5492,7 +5505,6 @@ public abstract class BaseTest { .columnType(TableColumnType.VARCHAR) .size(255L) .isNullAllowed(false) - .autoGenerated(false) .view(VIEW_5) .build(), ViewColumn.builder() @@ -5505,7 +5517,6 @@ public abstract class BaseTest { .size(10L) .d(0L) .isNullAllowed(true) - .autoGenerated(false) .view(VIEW_5) .build(), ViewColumn.builder() @@ -5518,7 +5529,6 @@ public abstract class BaseTest { .size(10L) .d(0L) .isNullAllowed(true) - .autoGenerated(false) .view(VIEW_5) .build()); @@ -7118,6 +7128,13 @@ public abstract class BaseTest { .user(USER_2) .build(); + public final static DatabaseAccessDto DATABASE_1_USER_2_READ_ACCESS_DTO = DatabaseAccessDto.builder() + .type(AccessTypeDto.READ) + .hdbid(DATABASE_1_ID) + .huserid(USER_2_ID) + .user(USER_2_DTO) + .build(); + public final static DatabaseAccess DATABASE_1_USER_2_WRITE_OWN_ACCESS = DatabaseAccess.builder() .type(AccessType.WRITE_OWN) .hdbid(DATABASE_1_ID) @@ -7141,6 +7158,13 @@ public abstract class BaseTest { .user(USER_2) .build(); + public final static DatabaseAccessDto DATABASE_1_USER_2_WRITE_ALL_ACCESS_DTO = DatabaseAccessDto.builder() + .type(AccessTypeDto.WRITE_ALL) + .hdbid(DATABASE_1_ID) + .huserid(USER_2_ID) + .user(USER_2_DTO) + .build(); + public final static DatabaseAccess DATABASE_1_USER_3_READ_ACCESS = DatabaseAccess.builder() .type(AccessType.READ) .hdbid(DATABASE_1_ID) diff --git a/dbrepo-metric-db/prometheus.yml b/dbrepo-metric-db/prometheus.yml new file mode 100644 index 0000000000000000000000000000000000000000..10df4f18959a0630be82ec22e44adbf13818f7bf --- /dev/null +++ b/dbrepo-metric-db/prometheus.yml @@ -0,0 +1,23 @@ +global: + scrape_interval: 1m + +rule_files: [] + +alerting: + alertmanagers: + - static_configs: + - targets: [] + +scrape_configs: + - job_name: 'java actuator scrape' + metrics_path: '/actuator/prometheus' + static_configs: + - targets: ['data-service:8080', 'metadata-service:8080'] + - job_name: 'metrics scrape' + metrics_path: '/metrics' + static_configs: + - targets: ['ui:3000', 'auth-service:9000', 'analyse-service:8080', 'search-service:8080', 'data-db-sidecar:8080', 'broker-service:15692', 'storage-service:9090', 'upload-service:8080', 'dashboard-service:3000'] +# - job_name: 'gateway scrape' +# metrics_path: '/metrics' +# static_configs: +# - targets: ['dbrepo-gateway-service-sidecar:9113'] diff --git a/dbrepo-search-service/.coveragerc b/dbrepo-search-service/.coveragerc new file mode 100644 index 0000000000000000000000000000000000000000..4683a93d3748d16ab20a61f318e3016d3f4a8e09 --- /dev/null +++ b/dbrepo-search-service/.coveragerc @@ -0,0 +1,5 @@ +[report] +omit = + */test/* + */omlib/* + */init/* \ No newline at end of file diff --git a/dbrepo-search-service/.gitignore b/dbrepo-search-service/.gitignore index 4acceedc9aee48621f76f34ea6dc297dae6065f4..78c8fdf6e56a9e006504b1f2345abdacbf6e7bb4 100644 --- a/dbrepo-search-service/.gitignore +++ b/dbrepo-search-service/.gitignore @@ -9,6 +9,14 @@ __pycache__/ # Generated coverage.txt report.xml +clients/ +omlib/ + +# Libraries +./lib/dbrepo-1.4.4* +./lib/dbrepo-1.4.5* +./lib/dbrepo-1.4.6* +./lib/dbrepo-1.4.7rc* # Distribution / packaging .Python diff --git a/dbrepo-search-service/Dockerfile b/dbrepo-search-service/Dockerfile index 35427f81a429f8a61bd724f7bb8141b734d5013f..9586d0be307c57572de9ece9667903fa92a8a7a8 100644 --- a/dbrepo-search-service/Dockerfile +++ b/dbrepo-search-service/Dockerfile @@ -17,8 +17,8 @@ USER 1001 WORKDIR /app -COPY --chown=1001 ./clients ./clients -COPY --chown=1001 ./omlib ./omlib +COPY --chown=1001 ./init/clients ./clients +COPY --chown=1001 ./init/omlib ./omlib COPY --chown=1001 ./os-yml ./os-yml COPY --chown=1001 ./app.py ./app.py COPY --chown=1001 ./friendly_names_overrides.json ./friendly_names_overrides.json diff --git a/dbrepo-search-service/Pipfile b/dbrepo-search-service/Pipfile index 8d6cc6b220d0e6df9219aeca9b7d1ec571c2fde6..e74391ce665a39201bd480819e31a712fe82a6c7 100644 --- a/dbrepo-search-service/Pipfile +++ b/dbrepo-search-service/Pipfile @@ -18,12 +18,13 @@ jwt = "~=1.3" testcontainers-opensearch = "*" pytest = "*" rdflib = "*" -dbrepo = {path = "./lib/dbrepo-1.4.5.tar.gz"} +dbrepo = {path = "./lib/dbrepo-1.4.7.tar.gz"} gunicorn = "*" [dev-packages] coverage = "*" pytest = "*" +requests-mock = "*" [requires] python_version = "3.11" diff --git a/dbrepo-search-service/Pipfile.lock b/dbrepo-search-service/Pipfile.lock index 8e2e1abc463a4f98a575e8acfe76194e74bbca74..123e864f6dd050a838ae2c7e9137a4d7b3f1e27f 100644 --- a/dbrepo-search-service/Pipfile.lock +++ b/dbrepo-search-service/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "f4b77f12b6e64d95ba5e3df0cce6f3eeb8d9cb8e45a6a17b46088d7077d13595" + "sha256": "491e5f6ada48e8af417dfa7d6a0b4d98ccf9b9072df53b44d8de014b687fc80c" }, "pipfile-spec": 6, "requires": { @@ -16,87 +16,110 @@ ] }, "default": { + "aiohappyeyeballs": { + "hashes": [ + "sha256:75cf88a15106a5002a8eb1dab212525c00d1f4c0fa96e551c9fbe6f09a621586", + "sha256:8a7a83727b2756f394ab2895ea0765a0a8c475e3c71e98d43d76f22b4b435572" + ], + "markers": "python_version >= '3.8'", + "version": "==2.4.3" + }, "aiohttp": { "hashes": [ - "sha256:0605cc2c0088fcaae79f01c913a38611ad09ba68ff482402d3410bf59039bfb8", - "sha256:0a158704edf0abcac8ac371fbb54044f3270bdbc93e254a82b6c82be1ef08f3c", - "sha256:0cbf56238f4bbf49dab8c2dc2e6b1b68502b1e88d335bea59b3f5b9f4c001475", - "sha256:1732102949ff6087589408d76cd6dea656b93c896b011ecafff418c9661dc4ed", - "sha256:18f634d540dd099c262e9f887c8bbacc959847cfe5da7a0e2e1cf3f14dbf2daf", - "sha256:239f975589a944eeb1bad26b8b140a59a3a320067fb3cd10b75c3092405a1372", - "sha256:2faa61a904b83142747fc6a6d7ad8fccff898c849123030f8e75d5d967fd4a81", - "sha256:320e8618eda64e19d11bdb3bd04ccc0a816c17eaecb7e4945d01deee2a22f95f", - "sha256:38d80498e2e169bc61418ff36170e0aad0cd268da8b38a17c4cf29d254a8b3f1", - "sha256:3916c8692dbd9d55c523374a3b8213e628424d19116ac4308e434dbf6d95bbdd", - "sha256:393c7aba2b55559ef7ab791c94b44f7482a07bf7640d17b341b79081f5e5cd1a", - "sha256:3b7b30258348082826d274504fbc7c849959f1989d86c29bc355107accec6cfb", - "sha256:3fcb4046d2904378e3aeea1df51f697b0467f2aac55d232c87ba162709478c46", - "sha256:4109adee842b90671f1b689901b948f347325045c15f46b39797ae1bf17019de", - "sha256:4558e5012ee03d2638c681e156461d37b7a113fe13970d438d95d10173d25f78", - "sha256:45731330e754f5811c314901cebdf19dd776a44b31927fa4b4dbecab9e457b0c", - "sha256:4715a9b778f4293b9f8ae7a0a7cef9829f02ff8d6277a39d7f40565c737d3771", - "sha256:471f0ef53ccedec9995287f02caf0c068732f026455f07db3f01a46e49d76bbb", - "sha256:4d3ebb9e1316ec74277d19c5f482f98cc65a73ccd5430540d6d11682cd857430", - "sha256:4ff550491f5492ab5ed3533e76b8567f4b37bd2995e780a1f46bca2024223233", - "sha256:52c27110f3862a1afbcb2af4281fc9fdc40327fa286c4625dfee247c3ba90156", - "sha256:55b39c8684a46e56ef8c8d24faf02de4a2b2ac60d26cee93bc595651ff545de9", - "sha256:5a7ee16aab26e76add4afc45e8f8206c95d1d75540f1039b84a03c3b3800dd59", - "sha256:5ca51eadbd67045396bc92a4345d1790b7301c14d1848feaac1d6a6c9289e888", - "sha256:5d6b3f1fabe465e819aed2c421a6743d8debbde79b6a8600739300630a01bf2c", - "sha256:60cdbd56f4cad9f69c35eaac0fbbdf1f77b0ff9456cebd4902f3dd1cf096464c", - "sha256:6380c039ec52866c06d69b5c7aad5478b24ed11696f0e72f6b807cfb261453da", - "sha256:639d0042b7670222f33b0028de6b4e2fad6451462ce7df2af8aee37dcac55424", - "sha256:66331d00fb28dc90aa606d9a54304af76b335ae204d1836f65797d6fe27f1ca2", - "sha256:67c3119f5ddc7261d47163ed86d760ddf0e625cd6246b4ed852e82159617b5fb", - "sha256:694d828b5c41255e54bc2dddb51a9f5150b4eefa9886e38b52605a05d96566e8", - "sha256:6ae79c1bc12c34082d92bf9422764f799aee4746fd7a392db46b7fd357d4a17a", - "sha256:702e2c7c187c1a498a4e2b03155d52658fdd6fda882d3d7fbb891a5cf108bb10", - "sha256:714d4e5231fed4ba2762ed489b4aec07b2b9953cf4ee31e9871caac895a839c0", - "sha256:7b179eea70833c8dee51ec42f3b4097bd6370892fa93f510f76762105568cf09", - "sha256:7f64cbd44443e80094309875d4f9c71d0401e966d191c3d469cde4642bc2e031", - "sha256:82a6a97d9771cb48ae16979c3a3a9a18b600a8505b1115cfe354dfb2054468b4", - "sha256:84dabd95154f43a2ea80deffec9cb44d2e301e38a0c9d331cc4aa0166fe28ae3", - "sha256:8676e8fd73141ded15ea586de0b7cda1542960a7b9ad89b2b06428e97125d4fa", - "sha256:88e311d98cc0bf45b62fc46c66753a83445f5ab20038bcc1b8a1cc05666f428a", - "sha256:8b4f72fbb66279624bfe83fd5eb6aea0022dad8eec62b71e7bf63ee1caadeafe", - "sha256:8c64a6dc3fe5db7b1b4d2b5cb84c4f677768bdc340611eca673afb7cf416ef5a", - "sha256:8cf142aa6c1a751fcb364158fd710b8a9be874b81889c2bd13aa8893197455e2", - "sha256:8d1964eb7617907c792ca00b341b5ec3e01ae8c280825deadbbd678447b127e1", - "sha256:93e22add827447d2e26d67c9ac0161756007f152fdc5210277d00a85f6c92323", - "sha256:9c69e77370cce2d6df5d12b4e12bdcca60c47ba13d1cbbc8645dd005a20b738b", - "sha256:9dbc053ac75ccc63dc3a3cc547b98c7258ec35a215a92bd9f983e0aac95d3d5b", - "sha256:9e3a1ae66e3d0c17cf65c08968a5ee3180c5a95920ec2731f53343fac9bad106", - "sha256:a6ea1a5b409a85477fd8e5ee6ad8f0e40bf2844c270955e09360418cfd09abac", - "sha256:a81b1143d42b66ffc40a441379387076243ef7b51019204fd3ec36b9f69e77d6", - "sha256:ad7f2919d7dac062f24d6f5fe95d401597fbb015a25771f85e692d043c9d7832", - "sha256:afc52b8d969eff14e069a710057d15ab9ac17cd4b6753042c407dcea0e40bf75", - "sha256:b3df71da99c98534be076196791adca8819761f0bf6e08e07fd7da25127150d6", - "sha256:c088c4d70d21f8ca5c0b8b5403fe84a7bc8e024161febdd4ef04575ef35d474d", - "sha256:c26959ca7b75ff768e2776d8055bf9582a6267e24556bb7f7bd29e677932be72", - "sha256:c413016880e03e69d166efb5a1a95d40f83d5a3a648d16486592c49ffb76d0db", - "sha256:c6021d296318cb6f9414b48e6a439a7f5d1f665464da507e8ff640848ee2a58a", - "sha256:c671dc117c2c21a1ca10c116cfcd6e3e44da7fcde37bf83b2be485ab377b25da", - "sha256:c7a4b7a6cf5b6eb11e109a9755fd4fda7d57395f8c575e166d363b9fc3ec4678", - "sha256:c8a02fbeca6f63cb1f0475c799679057fc9268b77075ab7cf3f1c600e81dd46b", - "sha256:cd2adf5c87ff6d8b277814a28a535b59e20bfea40a101db6b3bdca7e9926bc24", - "sha256:d1469f228cd9ffddd396d9948b8c9cd8022b6d1bf1e40c6f25b0fb90b4f893ed", - "sha256:d153f652a687a8e95ad367a86a61e8d53d528b0530ef382ec5aaf533140ed00f", - "sha256:d5ab8e1f6bee051a4bf6195e38a5c13e5e161cb7bad83d8854524798bd9fcd6e", - "sha256:da00da442a0e31f1c69d26d224e1efd3a1ca5bcbf210978a2ca7426dfcae9f58", - "sha256:da22dab31d7180f8c3ac7c7635f3bcd53808f374f6aa333fe0b0b9e14b01f91a", - "sha256:e0ae53e33ee7476dd3d1132f932eeb39bf6125083820049d06edcdca4381f342", - "sha256:e7a6a8354f1b62e15d48e04350f13e726fa08b62c3d7b8401c0a1314f02e3558", - "sha256:e9a3d838441bebcf5cf442700e3963f58b5c33f015341f9ea86dcd7d503c07e2", - "sha256:edea7d15772ceeb29db4aff55e482d4bcfb6ae160ce144f2682de02f6d693551", - "sha256:f22eb3a6c1080d862befa0a89c380b4dafce29dc6cd56083f630073d102eb595", - "sha256:f26383adb94da5e7fb388d441bf09c61e5e35f455a3217bfd790c6b6bc64b2ee", - "sha256:f3c2890ca8c59ee683fd09adf32321a40fe1cf164e3387799efb2acebf090c11", - "sha256:f64fd07515dad67f24b6ea4a66ae2876c01031de91c93075b8093f07c0a2d93d", - "sha256:fcde4c397f673fdec23e6b05ebf8d4751314fa7c24f93334bf1f1364c1c69ac7", - "sha256:ff84aeb864e0fac81f676be9f4685f0527b660f1efdc40dcede3c251ef1e867f" + "sha256:007ec22fbc573e5eb2fb7dec4198ef8f6bf2fe4ce20020798b2eb5d0abda6138", + "sha256:00819de9e45d42584bed046314c40ea7e9aea95411b38971082cad449392b08c", + "sha256:01948b1d570f83ee7bbf5a60ea2375a89dfb09fd419170e7f5af029510033d24", + "sha256:038f514fe39e235e9fef6717fbf944057bfa24f9b3db9ee551a7ecf584b5b480", + "sha256:03a42ac7895406220124c88911ebee31ba8b2d24c98507f4a8bf826b2937c7f2", + "sha256:05646ebe6b94cc93407b3bf34b9eb26c20722384d068eb7339de802154d61bc5", + "sha256:0631dd7c9f0822cc61c88586ca76d5b5ada26538097d0f1df510b082bad3411a", + "sha256:0b00807e2605f16e1e198f33a53ce3c4523114059b0c09c337209ae55e3823a8", + "sha256:0e1b370d8007c4ae31ee6db7f9a2fe801a42b146cec80a86766e7ad5c4a259cf", + "sha256:15ecd889a709b0080f02721255b3f80bb261c2293d3c748151274dfea93ac871", + "sha256:1b66ccafef7336a1e1f0e389901f60c1d920102315a56df85e49552308fc0486", + "sha256:1bbb122c557a16fafc10354b9d99ebf2f2808a660d78202f10ba9d50786384b9", + "sha256:1eb89d3d29adaf533588f209768a9c02e44e4baf832b08118749c5fad191781d", + "sha256:258c5dd01afc10015866114e210fb7365f0d02d9d059c3c3415382ab633fcbcb", + "sha256:2609e9ab08474702cc67b7702dbb8a80e392c54613ebe80db7e8dbdb79837c68", + "sha256:274cfa632350225ce3fdeb318c23b4a10ec25c0e2c880eff951a3842cf358ac1", + "sha256:28529e08fde6f12eba8677f5a8608500ed33c086f974de68cc65ab218713a59d", + "sha256:2b606353da03edcc71130b52388d25f9a30a126e04caef1fd637e31683033abd", + "sha256:30ca7c3b94708a9d7ae76ff281b2f47d8eaf2579cd05971b5dc681db8caac6e1", + "sha256:333cf6cf8e65f6a1e06e9eb3e643a0c515bb850d470902274239fea02033e9a8", + "sha256:3455522392fb15ff549d92fbf4b73b559d5e43dc522588f7eb3e54c3f38beee7", + "sha256:362f641f9071e5f3ee6f8e7d37d5ed0d95aae656adf4ef578313ee585b585959", + "sha256:3bcd391d083f636c06a68715e69467963d1f9600f85ef556ea82e9ef25f043f7", + "sha256:3dffb610a30d643983aeb185ce134f97f290f8935f0abccdd32c77bed9388b42", + "sha256:3fe407bf93533a6fa82dece0e74dbcaaf5d684e5a51862887f9eaebe6372cd79", + "sha256:413251f6fcf552a33c981c4709a6bba37b12710982fec8e558ae944bfb2abd38", + "sha256:438cd072f75bb6612f2aca29f8bd7cdf6e35e8f160bc312e49fbecab77c99e3a", + "sha256:4470c73c12cd9109db8277287d11f9dd98f77fc54155fc71a7738a83ffcc8ea8", + "sha256:45c3b868724137f713a38376fef8120c166d1eadd50da1855c112fe97954aed8", + "sha256:486f7aabfa292719a2753c016cc3a8f8172965cabb3ea2e7f7436c7f5a22a151", + "sha256:4f05e9727ce409358baa615dbeb9b969db94324a79b5a5cea45d39bdb01d82e6", + "sha256:50aed5155f819873d23520919e16703fc8925e509abbb1a1491b0087d1cd969e", + "sha256:50edbcad60d8f0e3eccc68da67f37268b5144ecc34d59f27a02f9611c1d4eec7", + "sha256:54ca74df1be3c7ca1cf7f4c971c79c2daf48d9aa65dea1a662ae18926f5bc8ce", + "sha256:578a4b875af3e0daaf1ac6fa983d93e0bbfec3ead753b6d6f33d467100cdc67b", + "sha256:597a079284b7ee65ee102bc3a6ea226a37d2b96d0418cc9047490f231dc09fe8", + "sha256:59bb3c54aa420521dc4ce3cc2c3fe2ad82adf7b09403fa1f48ae45c0cbde6628", + "sha256:5c6a5b8c7926ba5d8545c7dd22961a107526562da31a7a32fa2456baf040939f", + "sha256:64f6c17757251e2b8d885d728b6433d9d970573586a78b78ba8929b0f41d045a", + "sha256:679abe5d3858b33c2cf74faec299fda60ea9de62916e8b67e625d65bf069a3b7", + "sha256:741a46d58677d8c733175d7e5aa618d277cd9d880301a380fd296975a9cdd7bc", + "sha256:7789050d9e5d0c309c706953e5e8876e38662d57d45f936902e176d19f1c58ab", + "sha256:77abf6665ae54000b98b3c742bc6ea1d1fb31c394bcabf8b5d2c1ac3ebfe7f3b", + "sha256:79019094f87c9fb44f8d769e41dbb664d6e8fcfd62f665ccce36762deaa0e911", + "sha256:7b06b7843929e41a94ea09eb1ce3927865387e3e23ebe108e0d0d09b08d25be9", + "sha256:7e338c0523d024fad378b376a79faff37fafb3c001872a618cde1d322400a572", + "sha256:7ea7ffc6d6d6f8a11e6f40091a1040995cdff02cfc9ba4c2f30a516cb2633554", + "sha256:8105fd8a890df77b76dd3054cddf01a879fc13e8af576805d667e0fa0224c35d", + "sha256:84afcdea18eda514c25bc68b9af2a2b1adea7c08899175a51fe7c4fb6d551257", + "sha256:9294bbb581f92770e6ed5c19559e1e99255e4ca604a22c5c6397b2f9dd3ee42c", + "sha256:93429602396f3383a797a2a70e5f1de5df8e35535d7806c9f91df06f297e109b", + "sha256:9627cc1a10c8c409b5822a92d57a77f383b554463d1884008e051c32ab1b3742", + "sha256:998f3bd3cfc95e9424a6acd7840cbdd39e45bc09ef87533c006f94ac47296090", + "sha256:9c72109213eb9d3874f7ac8c0c5fa90e072d678e117d9061c06e30c85b4cf0e6", + "sha256:9fc1500fd2a952c5c8e3b29aaf7e3cc6e27e9cfc0a8819b3bce48cc1b849e4cc", + "sha256:a3f00003de6eba42d6e94fabb4125600d6e484846dbf90ea8e48a800430cc142", + "sha256:a45d85cf20b5e0d0aa5a8dca27cce8eddef3292bc29d72dcad1641f4ed50aa16", + "sha256:a7d8d14fe962153fc681f6366bdec33d4356f98a3e3567782aac1b6e0e40109a", + "sha256:a8fa23fe62c436ccf23ff930149c047f060c7126eae3ccea005f0483f27b2e28", + "sha256:aa6658732517ddabe22c9036479eabce6036655ba87a0224c612e1ae6af2087e", + "sha256:aafc8ee9b742ce75044ae9a4d3e60e3d918d15a4c2e08a6c3c3e38fa59b92d94", + "sha256:ab5a5a0c7a7991d90446a198689c0535be89bbd6b410a1f9a66688f0880ec026", + "sha256:acd48d5b80ee80f9432a165c0ac8cbf9253eaddb6113269a5e18699b33958dbb", + "sha256:ad7593bb24b2ab09e65e8a1d385606f0f47c65b5a2ae6c551db67d6653e78c28", + "sha256:baa42524a82f75303f714108fea528ccacf0386af429b69fff141ffef1c534f9", + "sha256:bdfcf6443637c148c4e1a20c48c566aa694fa5e288d34b20fcdc58507882fed3", + "sha256:be7443669ae9c016b71f402e43208e13ddf00912f47f623ee5994e12fc7d4b3f", + "sha256:c02a30b904282777d872266b87b20ed8cc0d1501855e27f831320f471d54d983", + "sha256:c1277cd707c465cd09572a774559a3cc7c7a28802eb3a2a9472588f062097205", + "sha256:c30a0eafc89d28e7f959281b58198a9fa5e99405f716c0289b7892ca345fe45f", + "sha256:c5ce2ce7c997e1971b7184ee37deb6ea9922ef5163c6ee5aa3c274b05f9e12fa", + "sha256:c823bc3971c44ab93e611ab1a46b1eafeae474c0c844aff4b7474287b75fe49c", + "sha256:ce0cdc074d540265bfeb31336e678b4e37316849d13b308607efa527e981f5c2", + "sha256:d1720b4f14c78a3089562b8875b53e36b51c97c51adc53325a69b79b4b48ebcb", + "sha256:d183cf9c797a5291e8301790ed6d053480ed94070637bfaad914dd38b0981f67", + "sha256:d9010c31cd6fa59438da4e58a7f19e4753f7f264300cd152e7f90d4602449762", + "sha256:d9e5e4a85bdb56d224f412d9c98ae4cbd032cc4f3161818f692cd81766eee65a", + "sha256:da1dee8948d2137bb51fbb8a53cce6b1bcc86003c6b42565f008438b806cccd8", + "sha256:df9270660711670e68803107d55c2b5949c2e0f2e4896da176e1ecfc068b974a", + "sha256:e00e3505cd80440f6c98c6d69269dcc2a119f86ad0a9fd70bccc59504bebd68a", + "sha256:e48d5021a84d341bcaf95c8460b152cfbad770d28e5fe14a768988c461b821bc", + "sha256:e7f8b04d83483577fd9200461b057c9f14ced334dcb053090cea1da9c8321a91", + "sha256:edfe3341033a6b53a5c522c802deb2079eee5cbfbb0af032a55064bd65c73a23", + "sha256:ef9c33cc5cbca35808f6c74be11eb7f5f6b14d2311be84a15b594bd3e58b5527", + "sha256:f2d4324a98062be0525d16f768a03e0bbb3b9fe301ceee99611dc9a7953124e6", + "sha256:f3935f82f6f4a3820270842e90456ebad3af15810cf65932bd24da4463bc0a4c", + "sha256:f614ab0c76397661b90b6851a030004dac502e48260ea10f2441abd2207fbcc7", + "sha256:f7db54c7914cc99d901d93a34704833568d86c20925b2762f9fa779f9cd2e70f", + "sha256:fbc6264158392bad9df19537e872d476f7c57adf718944cc1e4495cbabf38e2a", + "sha256:fe2fb38c2ed905a2582948e2de560675e9dfbee94c6d5ccdb1301c6d0a5bf092", + "sha256:ffe595f10566f8276b76dc3a11ae4bb7eba1aac8ddd75811736a15b0d5311414" ], "markers": "python_version >= '3.8'", - "version": "==3.9.5" + "version": "==3.10.10" }, "aiosignal": { "hashes": [ @@ -116,11 +139,11 @@ }, "attrs": { "hashes": [ - "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30", - "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1" + "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346", + "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2" ], "markers": "python_version >= '3.7'", - "version": "==23.2.0" + "version": "==24.2.0" }, "blinker": { "hashes": [ @@ -132,165 +155,195 @@ }, "certifi": { "hashes": [ - "sha256:3cd43f1c6fa7dedc5899d69d3ad0398fd018ad1a17fba83ddaf78aa46c747516", - "sha256:ddc6c8ce995e6987e7faf5e3f1b02b302836a0e5d98ece18392cb1a36c72ad56" + "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8", + "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9" ], "markers": "python_version >= '3.6'", - "version": "==2024.6.2" + "version": "==2024.8.30" }, "cffi": { "hashes": [ - "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc", - "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a", - "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417", - "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab", - "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520", - "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36", - "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743", - "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8", - "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed", - "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684", - "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56", - "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324", - "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d", - "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235", - "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e", - "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088", - "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000", - "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7", - "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e", - "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673", - "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c", - "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe", - "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2", - "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098", - "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8", - "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a", - "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0", - "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b", - "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896", - "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e", - "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9", - "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2", - "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b", - "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6", - "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404", - "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f", - "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0", - "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4", - "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc", - "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936", - "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba", - "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872", - "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb", - "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614", - "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1", - "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d", - "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969", - "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b", - "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4", - "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627", - "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956", - "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357" + "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8", + "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2", + "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1", + "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15", + "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36", + "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", + "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8", + "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36", + "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17", + "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf", + "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc", + "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3", + "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed", + "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702", + "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1", + "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8", + "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903", + "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6", + "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d", + "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b", + "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e", + "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be", + "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c", + "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683", + "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9", + "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c", + "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8", + "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1", + "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4", + "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655", + "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67", + "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595", + "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0", + "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65", + "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41", + "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6", + "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401", + "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6", + "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3", + "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16", + "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93", + "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e", + "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4", + "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964", + "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c", + "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576", + "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0", + "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3", + "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662", + "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3", + "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff", + "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5", + "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd", + "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f", + "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5", + "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14", + "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d", + "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9", + "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7", + "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382", + "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a", + "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e", + "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a", + "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4", + "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99", + "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87", + "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b" ], "markers": "platform_python_implementation != 'PyPy'", - "version": "==1.16.0" + "version": "==1.17.1" }, "charset-normalizer": { "hashes": [ - "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027", - "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087", - "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786", - "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8", - "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09", - "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185", - "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574", - "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e", - "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519", - "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898", - "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269", - "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3", - "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f", - "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6", - "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8", - "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a", - "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73", - "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc", - "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714", - "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2", - "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc", - "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce", - "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d", - "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e", - "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6", - "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269", - "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96", - "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d", - "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a", - "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4", - "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77", - "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d", - "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0", - "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed", - "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068", - "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac", - "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25", - "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8", - "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab", - "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26", - "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2", - "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db", - "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f", - "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5", - "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99", - "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c", - "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d", - "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811", - "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa", - "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a", - "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03", - "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b", - "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04", - "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c", - "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001", - "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458", - "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389", - "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99", - "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985", - "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537", - "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238", - "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f", - "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d", - "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796", - "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a", - "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143", - "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8", - "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c", - "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5", - "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5", - "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711", - "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4", - "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6", - "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c", - "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7", - "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4", - "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b", - "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae", - "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12", - "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c", - "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae", - "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8", - "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887", - "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b", - "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4", - "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f", - "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5", - "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33", - "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519", - "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561" + "sha256:0099d79bdfcf5c1f0c2c72f91516702ebf8b0b8ddd8905f97a8aecf49712c621", + "sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6", + "sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8", + "sha256:0b309d1747110feb25d7ed6b01afdec269c647d382c857ef4663bbe6ad95a912", + "sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c", + "sha256:0de7b687289d3c1b3e8660d0741874abe7888100efe14bd0f9fd7141bcbda92b", + "sha256:1110e22af8ca26b90bd6364fe4c763329b0ebf1ee213ba32b68c73de5752323d", + "sha256:130272c698667a982a5d0e626851ceff662565379baf0ff2cc58067b81d4f11d", + "sha256:136815f06a3ae311fae551c3df1f998a1ebd01ddd424aa5603a4336997629e95", + "sha256:14215b71a762336254351b00ec720a8e85cada43b987da5a042e4ce3e82bd68e", + "sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565", + "sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64", + "sha256:2006769bd1640bdf4d5641c69a3d63b71b81445473cac5ded39740a226fa88ab", + "sha256:20587d20f557fe189b7947d8e7ec5afa110ccf72a3128d61a2a387c3313f46be", + "sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e", + "sha256:27623ba66c183eca01bf9ff833875b459cad267aeeb044477fedac35e19ba907", + "sha256:285e96d9d53422efc0d7a17c60e59f37fbf3dfa942073f666db4ac71e8d726d0", + "sha256:2de62e8801ddfff069cd5c504ce3bc9672b23266597d4e4f50eda28846c322f2", + "sha256:2f6c34da58ea9c1a9515621f4d9ac379871a8f21168ba1b5e09d74250de5ad62", + "sha256:309a7de0a0ff3040acaebb35ec45d18db4b28232f21998851cfa709eeff49d62", + "sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23", + "sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc", + "sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284", + "sha256:40d3ff7fc90b98c637bda91c89d51264a3dcf210cade3a2c6f838c7268d7a4ca", + "sha256:425c5f215d0eecee9a56cdb703203dda90423247421bf0d67125add85d0c4455", + "sha256:43193c5cda5d612f247172016c4bb71251c784d7a4d9314677186a838ad34858", + "sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b", + "sha256:47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594", + "sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc", + "sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db", + "sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b", + "sha256:4ec9dd88a5b71abfc74e9df5ebe7921c35cbb3b641181a531ca65cdb5e8e4dea", + "sha256:4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6", + "sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920", + "sha256:55f56e2ebd4e3bc50442fbc0888c9d8c94e4e06a933804e2af3e89e2f9c1c749", + "sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7", + "sha256:5d447056e2ca60382d460a604b6302d8db69476fd2015c81e7c35417cfabe4cd", + "sha256:5ed2e36c3e9b4f21dd9422f6893dec0abf2cca553af509b10cd630f878d3eb99", + "sha256:5ff2ed8194587faf56555927b3aa10e6fb69d931e33953943bc4f837dfee2242", + "sha256:62f60aebecfc7f4b82e3f639a7d1433a20ec32824db2199a11ad4f5e146ef5ee", + "sha256:63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129", + "sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2", + "sha256:6b493a043635eb376e50eedf7818f2f322eabbaa974e948bd8bdd29eb7ef2a51", + "sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee", + "sha256:6fd30dc99682dc2c603c2b315bded2799019cea829f8bf57dc6b61efde6611c8", + "sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b", + "sha256:7706f5850360ac01d80c89bcef1640683cc12ed87f42579dab6c5d3ed6888613", + "sha256:7782afc9b6b42200f7362858f9e73b1f8316afb276d316336c0ec3bd73312742", + "sha256:79983512b108e4a164b9c8d34de3992f76d48cadc9554c9e60b43f308988aabe", + "sha256:7f683ddc7eedd742e2889d2bfb96d69573fde1d92fcb811979cdb7165bb9c7d3", + "sha256:82357d85de703176b5587dbe6ade8ff67f9f69a41c0733cf2425378b49954de5", + "sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631", + "sha256:86f4e8cca779080f66ff4f191a685ced73d2f72d50216f7112185dc02b90b9b7", + "sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15", + "sha256:8ce7fd6767a1cc5a92a639b391891bf1c268b03ec7e021c7d6d902285259685c", + "sha256:8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea", + "sha256:9289fd5dddcf57bab41d044f1756550f9e7cf0c8e373b8cdf0ce8773dc4bd417", + "sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250", + "sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88", + "sha256:95c3c157765b031331dd4db3c775e58deaee050a3042fcad72cbc4189d7c8dca", + "sha256:980b4f289d1d90ca5efcf07958d3eb38ed9c0b7676bf2831a54d4f66f9c27dfa", + "sha256:9ae4ef0b3f6b41bad6366fb0ea4fc1d7ed051528e113a60fa2a65a9abb5b1d99", + "sha256:9c98230f5042f4945f957d006edccc2af1e03ed5e37ce7c373f00a5a4daa6149", + "sha256:9fa2566ca27d67c86569e8c85297aaf413ffab85a8960500f12ea34ff98e4c41", + "sha256:a14969b8691f7998e74663b77b4c36c0337cb1df552da83d5c9004a93afdb574", + "sha256:a8aacce6e2e1edcb6ac625fb0f8c3a9570ccc7bfba1f63419b3769ccf6a00ed0", + "sha256:a8e538f46104c815be19c975572d74afb53f29650ea2025bbfaef359d2de2f7f", + "sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d", + "sha256:aa693779a8b50cd97570e5a0f343538a8dbd3e496fa5dcb87e29406ad0299654", + "sha256:ab22fbd9765e6954bc0bcff24c25ff71dcbfdb185fcdaca49e81bac68fe724d3", + "sha256:ab2e5bef076f5a235c3774b4f4028a680432cded7cad37bba0fd90d64b187d19", + "sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90", + "sha256:af73657b7a68211996527dbfeffbb0864e043d270580c5aef06dc4b659a4b578", + "sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9", + "sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1", + "sha256:b8831399554b92b72af5932cdbbd4ddc55c55f631bb13ff8fe4e6536a06c5c51", + "sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719", + "sha256:bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236", + "sha256:bd7af3717683bea4c87acd8c0d3d5b44d56120b26fd3f8a692bdd2d5260c620a", + "sha256:bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c", + "sha256:c3e446d253bd88f6377260d07c895816ebf33ffffd56c1c792b13bff9c3e1ade", + "sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944", + "sha256:c94057af19bc953643a33581844649a7fdab902624d2eb739738a30e2b3e60fc", + "sha256:cab5d0b79d987c67f3b9e9c53f54a61360422a5a0bc075f43cab5621d530c3b6", + "sha256:ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6", + "sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27", + "sha256:d5b054862739d276e09928de37c79ddeec42a6e1bfc55863be96a36ba22926f6", + "sha256:dbe03226baf438ac4fda9e2d0715022fd579cb641c4cf639fa40d53b2fe6f3e2", + "sha256:dc15e99b2d8a656f8e666854404f1ba54765871104e50c8e9813af8a7db07f12", + "sha256:dcaf7c1524c0542ee2fc82cc8ec337f7a9f7edee2532421ab200d2b920fc97cf", + "sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114", + "sha256:dd9a8bd8900e65504a305bf8ae6fa9fbc66de94178c420791d0293702fce2df7", + "sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf", + "sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d", + "sha256:e91f541a85298cf35433bf66f3fab2a4a2cff05c127eeca4af174f6d497f0d4b", + "sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed", + "sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03", + "sha256:f09cb5a7bbe1ecae6e87901a2eb23e0256bb524a79ccc53eb0b7629fbe7677c4", + "sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67", + "sha256:f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365", + "sha256:f28f891ccd15c514a0981f3b9db9aa23d62fe1a99997512b0491d2ed323d229a", + "sha256:f3e73a4255342d4eb26ef6df01e3962e73aa29baa3124a8e824c5d3364a65748", + "sha256:f606a1881d2663630ea5b8ce2efe2111740df4b687bd78b34a8131baa007f79b", + "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079", + "sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482" ], "markers": "python_full_version >= '3.7.0'", - "version": "==3.3.2" + "version": "==3.4.0" }, "click": { "hashes": [ @@ -302,50 +355,42 @@ }, "cryptography": { "hashes": [ - "sha256:013629ae70b40af70c9a7a5db40abe5d9054e6f4380e50ce769947b73bf3caad", - "sha256:2346b911eb349ab547076f47f2e035fc8ff2c02380a7cbbf8d87114fa0f1c583", - "sha256:2f66d9cd9147ee495a8374a45ca445819f8929a3efcd2e3df6428e46c3cbb10b", - "sha256:2f88d197e66c65be5e42cd72e5c18afbfae3f741742070e3019ac8f4ac57262c", - "sha256:31f721658a29331f895a5a54e7e82075554ccfb8b163a18719d342f5ffe5ecb1", - "sha256:343728aac38decfdeecf55ecab3264b015be68fc2816ca800db649607aeee648", - "sha256:5226d5d21ab681f432a9c1cf8b658c0cb02533eece706b155e5fbd8a0cdd3949", - "sha256:57080dee41209e556a9a4ce60d229244f7a66ef52750f813bfbe18959770cfba", - "sha256:5a94eccb2a81a309806027e1670a358b99b8fe8bfe9f8d329f27d72c094dde8c", - "sha256:6b7c4f03ce01afd3b76cf69a5455caa9cfa3de8c8f493e0d3ab7d20611c8dae9", - "sha256:7016f837e15b0a1c119d27ecd89b3515f01f90a8615ed5e9427e30d9cdbfed3d", - "sha256:81884c4d096c272f00aeb1f11cf62ccd39763581645b0812e99a91505fa48e0c", - "sha256:81d8a521705787afe7a18d5bfb47ea9d9cc068206270aad0b96a725022e18d2e", - "sha256:8d09d05439ce7baa8e9e95b07ec5b6c886f548deb7e0f69ef25f64b3bce842f2", - "sha256:961e61cefdcb06e0c6d7e3a1b22ebe8b996eb2bf50614e89384be54c48c6b63d", - "sha256:9c0c1716c8447ee7dbf08d6db2e5c41c688544c61074b54fc4564196f55c25a7", - "sha256:a0608251135d0e03111152e41f0cc2392d1e74e35703960d4190b2e0f4ca9c70", - "sha256:a0c5b2b0585b6af82d7e385f55a8bc568abff8923af147ee3c07bd8b42cda8b2", - "sha256:ad803773e9df0b92e0a817d22fd8a3675493f690b96130a5e24f1b8fabbea9c7", - "sha256:b297f90c5723d04bcc8265fc2a0f86d4ea2e0f7ab4b6994459548d3a6b992a14", - "sha256:ba4f0a211697362e89ad822e667d8d340b4d8d55fae72cdd619389fb5912eefe", - "sha256:c4783183f7cb757b73b2ae9aed6599b96338eb957233c58ca8f49a49cc32fd5e", - "sha256:c9bb2ae11bfbab395bdd072985abde58ea9860ed84e59dbc0463a5d0159f5b71", - "sha256:cafb92b2bc622cd1aa6a1dce4b93307792633f4c5fe1f46c6b97cf67073ec961", - "sha256:d45b940883a03e19e944456a558b67a41160e367a719833c53de6911cabba2b7", - "sha256:dc0fdf6787f37b1c6b08e6dfc892d9d068b5bdb671198c72072828b80bd5fe4c", - "sha256:dea567d1b0e8bc5764b9443858b673b734100c2871dc93163f58c46a97a83d28", - "sha256:dec9b018df185f08483f294cae6ccac29e7a6e0678996587363dc352dc65c842", - "sha256:e3ec3672626e1b9e55afd0df6d774ff0e953452886e06e0f1eb7eb0c832e8902", - "sha256:e599b53fd95357d92304510fb7bda8523ed1f79ca98dce2f43c115950aa78801", - "sha256:fa76fbb7596cc5839320000cdd5d0955313696d9511debab7ee7278fc8b5c84a", - "sha256:fff12c88a672ab9c9c1cf7b0c80e3ad9e2ebd9d828d955c126be4fd3e5578c9e" + "sha256:014f58110f53237ace6a408b5beb6c427b64e084eb451ef25a28308270086494", + "sha256:1bbcce1a551e262dfbafb6e6252f1ae36a248e615ca44ba302df077a846a8806", + "sha256:203e92a75716d8cfb491dc47c79e17d0d9207ccffcbcb35f598fbe463ae3444d", + "sha256:27e613d7077ac613e399270253259d9d53872aaf657471473ebfc9a52935c062", + "sha256:2bd51274dcd59f09dd952afb696bf9c61a7a49dfc764c04dd33ef7a6b502a1e2", + "sha256:38926c50cff6f533f8a2dae3d7f19541432610d114a70808f0926d5aaa7121e4", + "sha256:511f4273808ab590912a93ddb4e3914dfd8a388fed883361b02dea3791f292e1", + "sha256:58d4e9129985185a06d849aa6df265bdd5a74ca6e1b736a77959b498e0505b85", + "sha256:5b43d1ea6b378b54a1dc99dd8a2b5be47658fe9a7ce0a58ff0b55f4b43ef2b84", + "sha256:61ec41068b7b74268fa86e3e9e12b9f0c21fcf65434571dbb13d954bceb08042", + "sha256:666ae11966643886c2987b3b721899d250855718d6d9ce41b521252a17985f4d", + "sha256:68aaecc4178e90719e95298515979814bda0cbada1256a4485414860bd7ab962", + "sha256:7c05650fe8023c5ed0d46793d4b7d7e6cd9c04e68eabe5b0aeea836e37bdcec2", + "sha256:80eda8b3e173f0f247f711eef62be51b599b5d425c429b5d4ca6a05e9e856baa", + "sha256:8385d98f6a3bf8bb2d65a73e17ed87a3ba84f6991c155691c51112075f9ffc5d", + "sha256:88cce104c36870d70c49c7c8fd22885875d950d9ee6ab54df2745f83ba0dc365", + "sha256:9d3cdb25fa98afdd3d0892d132b8d7139e2c087da1712041f6b762e4f807cc96", + "sha256:a575913fb06e05e6b4b814d7f7468c2c660e8bb16d8d5a1faf9b33ccc569dd47", + "sha256:ac119bb76b9faa00f48128b7f5679e1d8d437365c5d26f1c2c3f0da4ce1b553d", + "sha256:c1332724be35d23a854994ff0b66530119500b6053d0bd3363265f7e5e77288d", + "sha256:d03a475165f3134f773d1388aeb19c2d25ba88b6a9733c5c590b9ff7bbfa2e0c", + "sha256:d75601ad10b059ec832e78823b348bfa1a59f6b8d545db3a24fd44362a1564cb", + "sha256:de41fd81a41e53267cb020bb3a7212861da53a7d39f863585d13ea11049cf277", + "sha256:e710bf40870f4db63c3d7d929aa9e09e4e7ee219e703f949ec4073b4294f6172", + "sha256:ea25acb556320250756e53f9e20a4177515f012c9eaea17eb7587a8c4d8ae034", + "sha256:f98bf604c82c416bc829e490c700ca1553eafdf2912a91e23a79d97d9801372a", + "sha256:fba1007b3ef89946dbbb515aeeb41e30203b004f0b4b00e5e16078b518563289" ], "markers": "python_version >= '3.7'", - "version": "==42.0.8" + "version": "==43.0.1" }, "dbrepo": { "hashes": [ - "sha256:09a10584a44c952a7cf83852123c14bd2917ab009e50698c1f9d8c2690ec4bde", - "sha256:2bdb48c70b4c99b5044fbfc12aa653c1e9281ca8913a433cc08a1e14cb4bd2ef", - "sha256:dccfaec20a3972a578313206678a119db3d6f898604aab4b694aa2ac37a20629" + "sha256:84607677b0826bb9b2fa120aacdf56d16c8d9ae423f435b2bd2c22b1c965a33c" ], - "path": "./lib/dbrepo-1.4.5.tar.gz", - "version": "==1.4.5" + "path": "./lib/dbrepo-1.4.7.tar.gz" }, "docker": { "hashes": [ @@ -374,15 +419,16 @@ "sha256:f69fcd559dc907ed196ab9df0e48471709175e696d6e698dd4dbe940f96ce66b" ], "index": "pypi", + "markers": "python_version >= '3.8'", "version": "==2.3.3" }, "flask-cors": { "hashes": [ - "sha256:eeb69b342142fdbf4766ad99357a7f3876a2ceb77689dc10ff912aac06c389e4", - "sha256:f2a704e4458665580c074b714c4627dd5a306b333deb9074d0b1794dfa2fb677" + "sha256:38364faf1a7a5d0a55bd1d2e2f83ee9e359039182f5e6a029557e1f56d92c09a", + "sha256:493b98e2d1e2f1a4720a7af25693ef2fe32fbafec09a2f72c59f3e475eda61d2" ], "index": "pypi", - "version": "==4.0.1" + "version": "==4.0.2" }, "flask-httpauth": { "hashes": [ @@ -398,6 +444,7 @@ "sha256:9215d05a9413d3855764bcd67035e75819d23af2fafb6b55197eb5a3313fdfb2" ], "index": "pypi", + "markers": "python_version >= '3.7' and python_version < '4'", "version": "==4.6.0" }, "flask-sqlalchemy": { @@ -406,6 +453,7 @@ "sha256:e4b68bb881802dda1a7d878b2fc84c06d1ee57fb40b874d3dc97dabfa36b8312" ], "index": "pypi", + "markers": "python_version >= '3.8'", "version": "==3.1.1" }, "frozenlist": { @@ -493,83 +541,99 @@ }, "greenlet": { "hashes": [ - "sha256:01bc7ea167cf943b4c802068e178bbf70ae2e8c080467070d01bfa02f337ee67", - "sha256:0448abc479fab28b00cb472d278828b3ccca164531daab4e970a0458786055d6", - "sha256:086152f8fbc5955df88382e8a75984e2bb1c892ad2e3c80a2508954e52295257", - "sha256:098d86f528c855ead3479afe84b49242e174ed262456c342d70fc7f972bc13c4", - "sha256:149e94a2dd82d19838fe4b2259f1b6b9957d5ba1b25640d2380bea9c5df37676", - "sha256:1551a8195c0d4a68fac7a4325efac0d541b48def35feb49d803674ac32582f61", - "sha256:15d79dd26056573940fcb8c7413d84118086f2ec1a8acdfa854631084393efcc", - "sha256:1996cb9306c8595335bb157d133daf5cf9f693ef413e7673cb07e3e5871379ca", - "sha256:1a7191e42732df52cb5f39d3527217e7ab73cae2cb3694d241e18f53d84ea9a7", - "sha256:1ea188d4f49089fc6fb283845ab18a2518d279c7cd9da1065d7a84e991748728", - "sha256:1f672519db1796ca0d8753f9e78ec02355e862d0998193038c7073045899f305", - "sha256:2516a9957eed41dd8f1ec0c604f1cdc86758b587d964668b5b196a9db5bfcde6", - "sha256:2797aa5aedac23af156bbb5a6aa2cd3427ada2972c828244eb7d1b9255846379", - "sha256:2dd6e660effd852586b6a8478a1d244b8dc90ab5b1321751d2ea15deb49ed414", - "sha256:3ddc0f794e6ad661e321caa8d2f0a55ce01213c74722587256fb6566049a8b04", - "sha256:3ed7fb269f15dc662787f4119ec300ad0702fa1b19d2135a37c2c4de6fadfd4a", - "sha256:419b386f84949bf0e7c73e6032e3457b82a787c1ab4a0e43732898a761cc9dbf", - "sha256:43374442353259554ce33599da8b692d5aa96f8976d567d4badf263371fbe491", - "sha256:52f59dd9c96ad2fc0d5724107444f76eb20aaccb675bf825df6435acb7703559", - "sha256:57e8974f23e47dac22b83436bdcf23080ade568ce77df33159e019d161ce1d1e", - "sha256:5b51e85cb5ceda94e79d019ed36b35386e8c37d22f07d6a751cb659b180d5274", - "sha256:649dde7de1a5eceb258f9cb00bdf50e978c9db1b996964cd80703614c86495eb", - "sha256:64d7675ad83578e3fc149b617a444fab8efdafc9385471f868eb5ff83e446b8b", - "sha256:68834da854554926fbedd38c76e60c4a2e3198c6fbed520b106a8986445caaf9", - "sha256:6b66c9c1e7ccabad3a7d037b2bcb740122a7b17a53734b7d72a344ce39882a1b", - "sha256:70fb482fdf2c707765ab5f0b6655e9cfcf3780d8d87355a063547b41177599be", - "sha256:7170375bcc99f1a2fbd9c306f5be8764eaf3ac6b5cb968862cad4c7057756506", - "sha256:73a411ef564e0e097dbe7e866bb2dda0f027e072b04da387282b02c308807405", - "sha256:77457465d89b8263bca14759d7c1684df840b6811b2499838cc5b040a8b5b113", - "sha256:7f362975f2d179f9e26928c5b517524e89dd48530a0202570d55ad6ca5d8a56f", - "sha256:81bb9c6d52e8321f09c3d165b2a78c680506d9af285bfccbad9fb7ad5a5da3e5", - "sha256:881b7db1ebff4ba09aaaeae6aa491daeb226c8150fc20e836ad00041bcb11230", - "sha256:894393ce10ceac937e56ec00bb71c4c2f8209ad516e96033e4b3b1de270e200d", - "sha256:99bf650dc5d69546e076f413a87481ee1d2d09aaaaaca058c9251b6d8c14783f", - "sha256:9da2bd29ed9e4f15955dd1595ad7bc9320308a3b766ef7f837e23ad4b4aac31a", - "sha256:afaff6cf5200befd5cec055b07d1c0a5a06c040fe5ad148abcd11ba6ab9b114e", - "sha256:b1b5667cced97081bf57b8fa1d6bfca67814b0afd38208d52538316e9422fc61", - "sha256:b37eef18ea55f2ffd8f00ff8fe7c8d3818abd3e25fb73fae2ca3b672e333a7a6", - "sha256:b542be2440edc2d48547b5923c408cbe0fc94afb9f18741faa6ae970dbcb9b6d", - "sha256:b7dcbe92cc99f08c8dd11f930de4d99ef756c3591a5377d1d9cd7dd5e896da71", - "sha256:b7f009caad047246ed379e1c4dbcb8b020f0a390667ea74d2387be2998f58a22", - "sha256:bba5387a6975598857d86de9eac14210a49d554a77eb8261cc68b7d082f78ce2", - "sha256:c5e1536de2aad7bf62e27baf79225d0d64360d4168cf2e6becb91baf1ed074f3", - "sha256:c5ee858cfe08f34712f548c3c363e807e7186f03ad7a5039ebadb29e8c6be067", - "sha256:c9db1c18f0eaad2f804728c67d6c610778456e3e1cc4ab4bbd5eeb8e6053c6fc", - "sha256:d353cadd6083fdb056bb46ed07e4340b0869c305c8ca54ef9da3421acbdf6881", - "sha256:d46677c85c5ba00a9cb6f7a00b2bfa6f812192d2c9f7d9c4f6a55b60216712f3", - "sha256:d4d1ac74f5c0c0524e4a24335350edad7e5f03b9532da7ea4d3c54d527784f2e", - "sha256:d73a9fe764d77f87f8ec26a0c85144d6a951a6c438dfe50487df5595c6373eac", - "sha256:da70d4d51c8b306bb7a031d5cff6cc25ad253affe89b70352af5f1cb68e74b53", - "sha256:daf3cb43b7cf2ba96d614252ce1684c1bccee6b2183a01328c98d36fcd7d5cb0", - "sha256:dca1e2f3ca00b84a396bc1bce13dd21f680f035314d2379c4160c98153b2059b", - "sha256:dd4f49ae60e10adbc94b45c0b5e6a179acc1736cf7a90160b404076ee283cf83", - "sha256:e1f145462f1fa6e4a4ae3c0f782e580ce44d57c8f2c7aae1b6fa88c0b2efdb41", - "sha256:e3391d1e16e2a5a1507d83e4a8b100f4ee626e8eca43cf2cadb543de69827c4c", - "sha256:fcd2469d6a2cf298f198f0487e0a5b1a47a42ca0fa4dfd1b6862c999f018ebbf", - "sha256:fd096eb7ffef17c456cfa587523c5f92321ae02427ff955bebe9e3c63bc9f0da", - "sha256:fe754d231288e1e64323cfad462fcee8f0288654c10bdf4f603a39ed923bef33" - ], - "markers": "python_version < '3.13' and platform_machine == 'aarch64' or (platform_machine == 'ppc64le' or (platform_machine == 'x86_64' or (platform_machine == 'amd64' or (platform_machine == 'AMD64' or (platform_machine == 'win32' or platform_machine == 'WIN32')))))", - "version": "==3.0.3" + "sha256:0153404a4bb921f0ff1abeb5ce8a5131da56b953eda6e14b88dc6bbc04d2049e", + "sha256:03a088b9de532cbfe2ba2034b2b85e82df37874681e8c470d6fb2f8c04d7e4b7", + "sha256:04b013dc07c96f83134b1e99888e7a79979f1a247e2a9f59697fa14b5862ed01", + "sha256:05175c27cb459dcfc05d026c4232f9de8913ed006d42713cb8a5137bd49375f1", + "sha256:09fc016b73c94e98e29af67ab7b9a879c307c6731a2c9da0db5a7d9b7edd1159", + "sha256:0bbae94a29c9e5c7e4a2b7f0aae5c17e8e90acbfd3bf6270eeba60c39fce3563", + "sha256:0fde093fb93f35ca72a556cf72c92ea3ebfda3d79fc35bb19fbe685853869a83", + "sha256:1443279c19fca463fc33e65ef2a935a5b09bb90f978beab37729e1c3c6c25fe9", + "sha256:1776fd7f989fc6b8d8c8cb8da1f6b82c5814957264d1f6cf818d475ec2bf6395", + "sha256:1d3755bcb2e02de341c55b4fca7a745a24a9e7212ac953f6b3a48d117d7257aa", + "sha256:23f20bb60ae298d7d8656c6ec6db134bca379ecefadb0b19ce6f19d1f232a942", + "sha256:275f72decf9932639c1c6dd1013a1bc266438eb32710016a1c742df5da6e60a1", + "sha256:2846930c65b47d70b9d178e89c7e1a69c95c1f68ea5aa0a58646b7a96df12441", + "sha256:3319aa75e0e0639bc15ff54ca327e8dc7a6fe404003496e3c6925cd3142e0e22", + "sha256:346bed03fe47414091be4ad44786d1bd8bef0c3fcad6ed3dee074a032ab408a9", + "sha256:36b89d13c49216cadb828db8dfa6ce86bbbc476a82d3a6c397f0efae0525bdd0", + "sha256:37b9de5a96111fc15418819ab4c4432e4f3c2ede61e660b1e33971eba26ef9ba", + "sha256:396979749bd95f018296af156201d6211240e7a23090f50a8d5d18c370084dc3", + "sha256:3b2813dc3de8c1ee3f924e4d4227999285fd335d1bcc0d2be6dc3f1f6a318ec1", + "sha256:411f015496fec93c1c8cd4e5238da364e1da7a124bcb293f085bf2860c32c6f6", + "sha256:47da355d8687fd65240c364c90a31569a133b7b60de111c255ef5b606f2ae291", + "sha256:48ca08c771c268a768087b408658e216133aecd835c0ded47ce955381105ba39", + "sha256:4afe7ea89de619adc868e087b4d2359282058479d7cfb94970adf4b55284574d", + "sha256:4ce3ac6cdb6adf7946475d7ef31777c26d94bccc377e070a7986bd2d5c515467", + "sha256:4ead44c85f8ab905852d3de8d86f6f8baf77109f9da589cb4fa142bd3b57b475", + "sha256:54558ea205654b50c438029505def3834e80f0869a70fb15b871c29b4575ddef", + "sha256:5e06afd14cbaf9e00899fae69b24a32f2196c19de08fcb9f4779dd4f004e5e7c", + "sha256:62ee94988d6b4722ce0028644418d93a52429e977d742ca2ccbe1c4f4a792511", + "sha256:63e4844797b975b9af3a3fb8f7866ff08775f5426925e1e0bbcfe7932059a12c", + "sha256:6510bf84a6b643dabba74d3049ead221257603a253d0a9873f55f6a59a65f822", + "sha256:667a9706c970cb552ede35aee17339a18e8f2a87a51fba2ed39ceeeb1004798a", + "sha256:6ef9ea3f137e5711f0dbe5f9263e8c009b7069d8a1acea822bd5e9dae0ae49c8", + "sha256:7017b2be767b9d43cc31416aba48aab0d2309ee31b4dbf10a1d38fb7972bdf9d", + "sha256:7124e16b4c55d417577c2077be379514321916d5790fa287c9ed6f23bd2ffd01", + "sha256:73aaad12ac0ff500f62cebed98d8789198ea0e6f233421059fa68a5aa7220145", + "sha256:77c386de38a60d1dfb8e55b8c1101d68c79dfdd25c7095d51fec2dd800892b80", + "sha256:7876452af029456b3f3549b696bb36a06db7c90747740c5302f74a9e9fa14b13", + "sha256:7939aa3ca7d2a1593596e7ac6d59391ff30281ef280d8632fa03d81f7c5f955e", + "sha256:8320f64b777d00dd7ccdade271eaf0cad6636343293a25074cc5566160e4de7b", + "sha256:85f3ff71e2e60bd4b4932a043fbbe0f499e263c628390b285cb599154a3b03b1", + "sha256:8b8b36671f10ba80e159378df9c4f15c14098c4fd73a36b9ad715f057272fbef", + "sha256:93147c513fac16385d1036b7e5b102c7fbbdb163d556b791f0f11eada7ba65dc", + "sha256:935e943ec47c4afab8965954bf49bfa639c05d4ccf9ef6e924188f762145c0ff", + "sha256:94b6150a85e1b33b40b1464a3f9988dcc5251d6ed06842abff82e42632fac120", + "sha256:94ebba31df2aa506d7b14866fed00ac141a867e63143fe5bca82a8e503b36437", + "sha256:95ffcf719966dd7c453f908e208e14cde192e09fde6c7186c8f1896ef778d8cd", + "sha256:98884ecf2ffb7d7fe6bd517e8eb99d31ff7855a840fa6d0d63cd07c037f6a981", + "sha256:99cfaa2110534e2cf3ba31a7abcac9d328d1d9f1b95beede58294a60348fba36", + "sha256:9e8f8c9cb53cdac7ba9793c276acd90168f416b9ce36799b9b885790f8ad6c0a", + "sha256:a0dfc6c143b519113354e780a50381508139b07d2177cb6ad6a08278ec655798", + "sha256:b2795058c23988728eec1f36a4e5e4ebad22f8320c85f3587b539b9ac84128d7", + "sha256:b42703b1cf69f2aa1df7d1030b9d77d3e584a70755674d60e710f0af570f3761", + "sha256:b7cede291382a78f7bb5f04a529cb18e068dd29e0fb27376074b6d0317bf4dd0", + "sha256:b8a678974d1f3aa55f6cc34dc480169d58f2e6d8958895d68845fa4ab566509e", + "sha256:b8da394b34370874b4572676f36acabac172602abf054cbc4ac910219f3340af", + "sha256:c3a701fe5a9695b238503ce5bbe8218e03c3bcccf7e204e455e7462d770268aa", + "sha256:c4aab7f6381f38a4b42f269057aee279ab0fc7bf2e929e3d4abfae97b682a12c", + "sha256:ca9d0ff5ad43e785350894d97e13633a66e2b50000e8a183a50a88d834752d42", + "sha256:d0028e725ee18175c6e422797c407874da24381ce0690d6b9396c204c7f7276e", + "sha256:d21e10da6ec19b457b82636209cbe2331ff4306b54d06fa04b7c138ba18c8a81", + "sha256:d5e975ca70269d66d17dd995dafc06f1b06e8cb1ec1e9ed54c1d1e4a7c4cf26e", + "sha256:da7a9bff22ce038e19bf62c4dd1ec8391062878710ded0a845bcf47cc0200617", + "sha256:db32b5348615a04b82240cc67983cb315309e88d444a288934ee6ceaebcad6cc", + "sha256:dcc62f31eae24de7f8dce72134c8651c58000d3b1868e01392baea7c32c247de", + "sha256:dfc59d69fc48664bc693842bd57acfdd490acafda1ab52c7836e3fc75c90a111", + "sha256:e347b3bfcf985a05e8c0b7d462ba6f15b1ee1c909e2dcad795e49e91b152c383", + "sha256:e4d333e558953648ca09d64f13e6d8f0523fa705f51cae3f03b5983489958c70", + "sha256:ed10eac5830befbdd0c32f83e8aa6288361597550ba669b04c48f0f9a2c843c6", + "sha256:efc0f674aa41b92da8c49e0346318c6075d734994c3c4e4430b1c3f853e498e4", + "sha256:f1695e76146579f8c06c1509c7ce4dfe0706f49c6831a817ac04eebb2fd02011", + "sha256:f1d4aeb8891338e60d1ab6127af1fe45def5259def8094b9c7e34690c8858803", + "sha256:f406b22b7c9a9b4f8aa9d2ab13d6ae0ac3e85c9a809bd590ad53fed2bf70dc79", + "sha256:f6ff3b14f2df4c41660a7dec01045a045653998784bf8cfcb5a525bdffffbc8f" + ], + "markers": "python_version < '3.13' and (platform_machine == 'aarch64' or (platform_machine == 'ppc64le' or (platform_machine == 'x86_64' or (platform_machine == 'amd64' or (platform_machine == 'AMD64' or (platform_machine == 'win32' or platform_machine == 'WIN32'))))))", + "version": "==3.1.1" }, "gunicorn": { "hashes": [ - "sha256:350679f91b24062c86e386e198a15438d53a7a8207235a78ba1b53df4c4378d9", - "sha256:4a0b436239ff76fb33f11c07a16482c521a7e09c1ce3cc293c2330afe01bec63" + "sha256:ec400d38950de4dfd418cff8328b2c8faed0edb0d517d3394e457c317908ca4d", + "sha256:f014447a0101dc57e294f6c18ca6b40227a4c90e9bdb586042628030cba004ec" ], "index": "pypi", - "version": "==22.0.0" + "markers": "python_version >= '3.7'", + "version": "==23.0.0" }, "idna": { "hashes": [ - "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc", - "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0" + "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", + "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3" ], - "markers": "python_version >= '3.5'", - "version": "==3.7" + "markers": "python_version >= '3.6'", + "version": "==3.10" }, "iniconfig": { "hashes": [ @@ -604,92 +668,94 @@ }, "jsonschema": { "hashes": [ - "sha256:5b22d434a45935119af990552c862e5d6d564e8f6601206b305a61fdf661a2b7", - "sha256:ff4cfd6b1367a40e7bc6411caec72effadd3db0bbe5017de188f2d6108335802" + "sha256:d71497fef26351a33265337fa77ffeb82423f3ea21283cd9467bb03999266bc4", + "sha256:fbadb6f8b144a8f8cf9f0b89ba94501d143e50411a1278633f56a7acf7fd5566" ], "markers": "python_version >= '3.8'", - "version": "==4.22.0" + "version": "==4.23.0" }, "jsonschema-specifications": { "hashes": [ - "sha256:48a76787b3e70f5ed53f1160d2b81f586e4ca6d1548c5de7085d1682674764cc", - "sha256:87e4fdf3a94858b8a2ba2778d9ba57d8a9cafca7c7489c46ba0d30a8bc6a9c3c" + "sha256:0f38b83639958ce1152d02a7f062902c41c8fd20d558b0c34344292d417ae272", + "sha256:a09a0680616357d9a0ecf05c12ad234479f549239d0f5b55f3deea67475da9bf" ], - "markers": "python_version >= '3.8'", - "version": "==2023.12.1" + "markers": "python_version >= '3.9'", + "version": "==2024.10.1" }, "jwt": { "hashes": [ "sha256:61c9170f92e736b530655e75374681d4fcca9cfa8763ab42be57353b2b203494" ], "index": "pypi", + "markers": "python_version >= '3.6'", "version": "==1.3.1" }, "markupsafe": { "hashes": [ - "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf", - "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff", - "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f", - "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3", - "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532", - "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f", - "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617", - "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df", - "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4", - "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906", - "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f", - "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4", - "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8", - "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371", - "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2", - "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465", - "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52", - "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6", - "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169", - "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad", - "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2", - "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0", - "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029", - "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f", - "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a", - "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced", - "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5", - "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c", - "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf", - "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9", - "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb", - "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad", - "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3", - "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1", - "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46", - "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc", - "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a", - "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee", - "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900", - "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5", - "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea", - "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f", - "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5", - "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e", - "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a", - "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f", - "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50", - "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a", - "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b", - "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4", - "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff", - "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2", - "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46", - "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b", - "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf", - "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5", - "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5", - "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab", - "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd", - "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68" + "sha256:0778de17cff1acaeccc3ff30cd99a3fd5c50fc58ad3d6c0e0c4c58092b859396", + "sha256:0f84af7e813784feb4d5e4ff7db633aba6c8ca64a833f61d8e4eade234ef0c38", + "sha256:17b2aea42a7280db02ac644db1d634ad47dcc96faf38ab304fe26ba2680d359a", + "sha256:242d6860f1fd9191aef5fae22b51c5c19767f93fb9ead4d21924e0bcb17619d8", + "sha256:244dbe463d5fb6d7ce161301a03a6fe744dac9072328ba9fc82289238582697b", + "sha256:26627785a54a947f6d7336ce5963569b5d75614619e75193bdb4e06e21d447ad", + "sha256:2a4b34a8d14649315c4bc26bbfa352663eb51d146e35eef231dd739d54a5430a", + "sha256:2ae99f31f47d849758a687102afdd05bd3d3ff7dbab0a8f1587981b58a76152a", + "sha256:312387403cd40699ab91d50735ea7a507b788091c416dd007eac54434aee51da", + "sha256:3341c043c37d78cc5ae6e3e305e988532b072329639007fd408a476642a89fd6", + "sha256:33d1c36b90e570ba7785dacd1faaf091203d9942bc036118fab8110a401eb1a8", + "sha256:3e683ee4f5d0fa2dde4db77ed8dd8a876686e3fc417655c2ece9a90576905344", + "sha256:3ffb4a8e7d46ed96ae48805746755fadd0909fea2306f93d5d8233ba23dda12a", + "sha256:40621d60d0e58aa573b68ac5e2d6b20d44392878e0bfc159012a5787c4e35bc8", + "sha256:40f1e10d51c92859765522cbd79c5c8989f40f0419614bcdc5015e7b6bf97fc5", + "sha256:45d42d132cff577c92bfba536aefcfea7e26efb975bd455db4e6602f5c9f45e7", + "sha256:48488d999ed50ba8d38c581d67e496f955821dc183883550a6fbc7f1aefdc170", + "sha256:4935dd7883f1d50e2ffecca0aa33dc1946a94c8f3fdafb8df5c330e48f71b132", + "sha256:4c2d64fdba74ad16138300815cfdc6ab2f4647e23ced81f59e940d7d4a1469d9", + "sha256:4c8817557d0de9349109acb38b9dd570b03cc5014e8aabf1cbddc6e81005becd", + "sha256:4ffaaac913c3f7345579db4f33b0020db693f302ca5137f106060316761beea9", + "sha256:5a4cb365cb49b750bdb60b846b0c0bc49ed62e59a76635095a179d440540c346", + "sha256:62fada2c942702ef8952754abfc1a9f7658a4d5460fabe95ac7ec2cbe0d02abc", + "sha256:67c519635a4f64e495c50e3107d9b4075aec33634272b5db1cde839e07367589", + "sha256:6a54c43d3ec4cf2a39f4387ad044221c66a376e58c0d0e971d47c475ba79c6b5", + "sha256:7044312a928a66a4c2a22644147bc61a199c1709712069a344a3fb5cfcf16915", + "sha256:730d86af59e0e43ce277bb83970530dd223bf7f2a838e086b50affa6ec5f9295", + "sha256:800100d45176652ded796134277ecb13640c1a537cad3b8b53da45aa96330453", + "sha256:80fcbf3add8790caddfab6764bde258b5d09aefbe9169c183f88a7410f0f6dea", + "sha256:82b5dba6eb1bcc29cc305a18a3c5365d2af06ee71b123216416f7e20d2a84e5b", + "sha256:852dc840f6d7c985603e60b5deaae1d89c56cb038b577f6b5b8c808c97580f1d", + "sha256:8ad4ad1429cd4f315f32ef263c1342166695fad76c100c5d979c45d5570ed58b", + "sha256:8ae369e84466aa70f3154ee23c1451fda10a8ee1b63923ce76667e3077f2b0c4", + "sha256:93e8248d650e7e9d49e8251f883eed60ecbc0e8ffd6349e18550925e31bd029b", + "sha256:973a371a55ce9ed333a3a0f8e0bcfae9e0d637711534bcb11e130af2ab9334e7", + "sha256:9ba25a71ebf05b9bb0e2ae99f8bc08a07ee8e98c612175087112656ca0f5c8bf", + "sha256:a10860e00ded1dd0a65b83e717af28845bb7bd16d8ace40fe5531491de76b79f", + "sha256:a4792d3b3a6dfafefdf8e937f14906a51bd27025a36f4b188728a73382231d91", + "sha256:a7420ceda262dbb4b8d839a4ec63d61c261e4e77677ed7c66c99f4e7cb5030dd", + "sha256:ad91738f14eb8da0ff82f2acd0098b6257621410dcbd4df20aaa5b4233d75a50", + "sha256:b6a387d61fe41cdf7ea95b38e9af11cfb1a63499af2759444b99185c4ab33f5b", + "sha256:b954093679d5750495725ea6f88409946d69cfb25ea7b4c846eef5044194f583", + "sha256:bbde71a705f8e9e4c3e9e33db69341d040c827c7afa6789b14c6e16776074f5a", + "sha256:beeebf760a9c1f4c07ef6a53465e8cfa776ea6a2021eda0d0417ec41043fe984", + "sha256:c91b394f7601438ff79a4b93d16be92f216adb57d813a78be4446fe0f6bc2d8c", + "sha256:c97ff7fedf56d86bae92fa0a646ce1a0ec7509a7578e1ed238731ba13aabcd1c", + "sha256:cb53e2a99df28eee3b5f4fea166020d3ef9116fdc5764bc5117486e6d1211b25", + "sha256:cbf445eb5628981a80f54087f9acdbf84f9b7d862756110d172993b9a5ae81aa", + "sha256:d06b24c686a34c86c8c1fba923181eae6b10565e4d80bdd7bc1c8e2f11247aa4", + "sha256:d98e66a24497637dd31ccab090b34392dddb1f2f811c4b4cd80c230205c074a3", + "sha256:db15ce28e1e127a0013dfb8ac243a8e392db8c61eae113337536edb28bdc1f97", + "sha256:db842712984e91707437461930e6011e60b39136c7331e971952bb30465bc1a1", + "sha256:e24bfe89c6ac4c31792793ad9f861b8f6dc4546ac6dc8f1c9083c7c4f2b335cd", + "sha256:e81c52638315ff4ac1b533d427f50bc0afc746deb949210bc85f05d4f15fd772", + "sha256:e9393357f19954248b00bed7c56f29a25c930593a77630c719653d51e7669c2a", + "sha256:ee3941769bd2522fe39222206f6dd97ae83c442a94c90f2b7a25d847d40f4729", + "sha256:f31ae06f1328595d762c9a2bf29dafd8621c7d3adc130cbb46278079758779ca", + "sha256:f94190df587738280d544971500b9cafc9b950d32efcb1fba9ac10d84e6aa4e6", + "sha256:fa7d686ed9883f3d664d39d5a8e74d3c5f63e603c2e3ff0abcba23eac6542635", + "sha256:fb532dd9900381d2e8f48172ddc5a59db4c445a11b9fab40b3b786da40d3b56b", + "sha256:fe32482b37b4b00c7a52a07211b479653b7fe4f22b2e481b9a9b099d8a430f2f" ], - "markers": "python_version >= '3.7'", - "version": "==2.1.5" + "markers": "python_version >= '3.9'", + "version": "==3.0.1" }, "mistune": { "hashes": [ @@ -701,158 +767,169 @@ }, "multidict": { "hashes": [ - "sha256:01265f5e40f5a17f8241d52656ed27192be03bfa8764d88e8220141d1e4b3556", - "sha256:0275e35209c27a3f7951e1ce7aaf93ce0d163b28948444bec61dd7badc6d3f8c", - "sha256:04bde7a7b3de05732a4eb39c94574db1ec99abb56162d6c520ad26f83267de29", - "sha256:04da1bb8c8dbadf2a18a452639771951c662c5ad03aefe4884775454be322c9b", - "sha256:09a892e4a9fb47331da06948690ae38eaa2426de97b4ccbfafbdcbe5c8f37ff8", - "sha256:0d63c74e3d7ab26de115c49bffc92cc77ed23395303d496eae515d4204a625e7", - "sha256:107c0cdefe028703fb5dafe640a409cb146d44a6ae201e55b35a4af8e95457dd", - "sha256:141b43360bfd3bdd75f15ed811850763555a251e38b2405967f8e25fb43f7d40", - "sha256:14c2976aa9038c2629efa2c148022ed5eb4cb939e15ec7aace7ca932f48f9ba6", - "sha256:19fe01cea168585ba0f678cad6f58133db2aa14eccaf22f88e4a6dccadfad8b3", - "sha256:1d147090048129ce3c453f0292e7697d333db95e52616b3793922945804a433c", - "sha256:1d9ea7a7e779d7a3561aade7d596649fbecfa5c08a7674b11b423783217933f9", - "sha256:215ed703caf15f578dca76ee6f6b21b7603791ae090fbf1ef9d865571039ade5", - "sha256:21fd81c4ebdb4f214161be351eb5bcf385426bf023041da2fd9e60681f3cebae", - "sha256:220dd781e3f7af2c2c1053da9fa96d9cf3072ca58f057f4c5adaaa1cab8fc442", - "sha256:228b644ae063c10e7f324ab1ab6b548bdf6f8b47f3ec234fef1093bc2735e5f9", - "sha256:29bfeb0dff5cb5fdab2023a7a9947b3b4af63e9c47cae2a10ad58394b517fddc", - "sha256:2f4848aa3baa109e6ab81fe2006c77ed4d3cd1e0ac2c1fbddb7b1277c168788c", - "sha256:2faa5ae9376faba05f630d7e5e6be05be22913782b927b19d12b8145968a85ea", - "sha256:2ffc42c922dbfddb4a4c3b438eb056828719f07608af27d163191cb3e3aa6cc5", - "sha256:37b15024f864916b4951adb95d3a80c9431299080341ab9544ed148091b53f50", - "sha256:3cc2ad10255f903656017363cd59436f2111443a76f996584d1077e43ee51182", - "sha256:3d25f19500588cbc47dc19081d78131c32637c25804df8414463ec908631e453", - "sha256:403c0911cd5d5791605808b942c88a8155c2592e05332d2bf78f18697a5fa15e", - "sha256:411bf8515f3be9813d06004cac41ccf7d1cd46dfe233705933dd163b60e37600", - "sha256:425bf820055005bfc8aa9a0b99ccb52cc2f4070153e34b701acc98d201693733", - "sha256:435a0984199d81ca178b9ae2c26ec3d49692d20ee29bc4c11a2a8d4514c67eda", - "sha256:4a6a4f196f08c58c59e0b8ef8ec441d12aee4125a7d4f4fef000ccb22f8d7241", - "sha256:4cc0ef8b962ac7a5e62b9e826bd0cd5040e7d401bc45a6835910ed699037a461", - "sha256:51d035609b86722963404f711db441cf7134f1889107fb171a970c9701f92e1e", - "sha256:53689bb4e102200a4fafa9de9c7c3c212ab40a7ab2c8e474491914d2305f187e", - "sha256:55205d03e8a598cfc688c71ca8ea5f66447164efff8869517f175ea632c7cb7b", - "sha256:5c0631926c4f58e9a5ccce555ad7747d9a9f8b10619621f22f9635f069f6233e", - "sha256:5cb241881eefd96b46f89b1a056187ea8e9ba14ab88ba632e68d7a2ecb7aadf7", - "sha256:60d698e8179a42ec85172d12f50b1668254628425a6bd611aba022257cac1386", - "sha256:612d1156111ae11d14afaf3a0669ebf6c170dbb735e510a7438ffe2369a847fd", - "sha256:6214c5a5571802c33f80e6c84713b2c79e024995b9c5897f794b43e714daeec9", - "sha256:6939c95381e003f54cd4c5516740faba40cf5ad3eeff460c3ad1d3e0ea2549bf", - "sha256:69db76c09796b313331bb7048229e3bee7928eb62bab5e071e9f7fcc4879caee", - "sha256:6bf7a982604375a8d49b6cc1b781c1747f243d91b81035a9b43a2126c04766f5", - "sha256:766c8f7511df26d9f11cd3a8be623e59cca73d44643abab3f8c8c07620524e4a", - "sha256:76c0de87358b192de7ea9649beb392f107dcad9ad27276324c24c91774ca5271", - "sha256:76f067f5121dcecf0d63a67f29080b26c43c71a98b10c701b0677e4a065fbd54", - "sha256:7901c05ead4b3fb75113fb1dd33eb1253c6d3ee37ce93305acd9d38e0b5f21a4", - "sha256:79660376075cfd4b2c80f295528aa6beb2058fd289f4c9252f986751a4cd0496", - "sha256:79a6d2ba910adb2cbafc95dad936f8b9386e77c84c35bc0add315b856d7c3abb", - "sha256:7afcdd1fc07befad18ec4523a782cde4e93e0a2bf71239894b8d61ee578c1319", - "sha256:7be7047bd08accdb7487737631d25735c9a04327911de89ff1b26b81745bd4e3", - "sha256:7c6390cf87ff6234643428991b7359b5f59cc15155695deb4eda5c777d2b880f", - "sha256:7df704ca8cf4a073334e0427ae2345323613e4df18cc224f647f251e5e75a527", - "sha256:85f67aed7bb647f93e7520633d8f51d3cbc6ab96957c71272b286b2f30dc70ed", - "sha256:896ebdcf62683551312c30e20614305f53125750803b614e9e6ce74a96232604", - "sha256:92d16a3e275e38293623ebf639c471d3e03bb20b8ebb845237e0d3664914caef", - "sha256:99f60d34c048c5c2fabc766108c103612344c46e35d4ed9ae0673d33c8fb26e8", - "sha256:9fe7b0653ba3d9d65cbe7698cca585bf0f8c83dbbcc710db9c90f478e175f2d5", - "sha256:a3145cb08d8625b2d3fee1b2d596a8766352979c9bffe5d7833e0503d0f0b5e5", - "sha256:aeaf541ddbad8311a87dd695ed9642401131ea39ad7bc8cf3ef3967fd093b626", - "sha256:b55358304d7a73d7bdf5de62494aaf70bd33015831ffd98bc498b433dfe5b10c", - "sha256:b82cc8ace10ab5bd93235dfaab2021c70637005e1ac787031f4d1da63d493c1d", - "sha256:c0868d64af83169e4d4152ec612637a543f7a336e4a307b119e98042e852ad9c", - "sha256:c1c1496e73051918fcd4f58ff2e0f2f3066d1c76a0c6aeffd9b45d53243702cc", - "sha256:c9bf56195c6bbd293340ea82eafd0071cb3d450c703d2c93afb89f93b8386ccc", - "sha256:cbebcd5bcaf1eaf302617c114aa67569dd3f090dd0ce8ba9e35e9985b41ac35b", - "sha256:cd6c8fca38178e12c00418de737aef1261576bd1b6e8c6134d3e729a4e858b38", - "sha256:ceb3b7e6a0135e092de86110c5a74e46bda4bd4fbfeeb3a3bcec79c0f861e450", - "sha256:cf590b134eb70629e350691ecca88eac3e3b8b3c86992042fb82e3cb1830d5e1", - "sha256:d3eb1ceec286eba8220c26f3b0096cf189aea7057b6e7b7a2e60ed36b373b77f", - "sha256:d65f25da8e248202bd47445cec78e0025c0fe7582b23ec69c3b27a640dd7a8e3", - "sha256:d6f6d4f185481c9669b9447bf9d9cf3b95a0e9df9d169bbc17e363b7d5487755", - "sha256:d84a5c3a5f7ce6db1f999fb9438f686bc2e09d38143f2d93d8406ed2dd6b9226", - "sha256:d946b0a9eb8aaa590df1fe082cee553ceab173e6cb5b03239716338629c50c7a", - "sha256:dce1c6912ab9ff5f179eaf6efe7365c1f425ed690b03341911bf4939ef2f3046", - "sha256:de170c7b4fe6859beb8926e84f7d7d6c693dfe8e27372ce3b76f01c46e489fcf", - "sha256:e02021f87a5b6932fa6ce916ca004c4d441509d33bbdbeca70d05dff5e9d2479", - "sha256:e030047e85cbcedbfc073f71836d62dd5dadfbe7531cae27789ff66bc551bd5e", - "sha256:e0e79d91e71b9867c73323a3444724d496c037e578a0e1755ae159ba14f4f3d1", - "sha256:e4428b29611e989719874670fd152b6625500ad6c686d464e99f5aaeeaca175a", - "sha256:e4972624066095e52b569e02b5ca97dbd7a7ddd4294bf4e7247d52635630dd83", - "sha256:e7be68734bd8c9a513f2b0cfd508802d6609da068f40dc57d4e3494cefc92929", - "sha256:e8e94e6912639a02ce173341ff62cc1201232ab86b8a8fcc05572741a5dc7d93", - "sha256:ea1456df2a27c73ce51120fa2f519f1bea2f4a03a917f4a43c8707cf4cbbae1a", - "sha256:ebd8d160f91a764652d3e51ce0d2956b38efe37c9231cd82cfc0bed2e40b581c", - "sha256:eca2e9d0cc5a889850e9bbd68e98314ada174ff6ccd1129500103df7a94a7a44", - "sha256:edd08e6f2f1a390bf137080507e44ccc086353c8e98c657e666c017718561b89", - "sha256:f285e862d2f153a70586579c15c44656f888806ed0e5b56b64489afe4a2dbfba", - "sha256:f2a1dee728b52b33eebff5072817176c172050d44d67befd681609b4746e1c2e", - "sha256:f7e301075edaf50500f0b341543c41194d8df3ae5caf4702f2095f3ca73dd8da", - "sha256:fb616be3538599e797a2017cccca78e354c767165e8858ab5116813146041a24", - "sha256:fce28b3c8a81b6b36dfac9feb1de115bab619b3c13905b419ec71d03a3fc1423", - "sha256:fe5d7785250541f7f5019ab9cba2c71169dc7d74d0f45253f8313f436458a4ef" + "sha256:052e10d2d37810b99cc170b785945421141bf7bb7d2f8799d431e7db229c385f", + "sha256:06809f4f0f7ab7ea2cabf9caca7d79c22c0758b58a71f9d32943ae13c7ace056", + "sha256:071120490b47aa997cca00666923a83f02c7fbb44f71cf7f136df753f7fa8761", + "sha256:0c3f390dc53279cbc8ba976e5f8035eab997829066756d811616b652b00a23a3", + "sha256:0e2b90b43e696f25c62656389d32236e049568b39320e2735d51f08fd362761b", + "sha256:0e5f362e895bc5b9e67fe6e4ded2492d8124bdf817827f33c5b46c2fe3ffaca6", + "sha256:10524ebd769727ac77ef2278390fb0068d83f3acb7773792a5080f2b0abf7748", + "sha256:10a9b09aba0c5b48c53761b7c720aaaf7cf236d5fe394cd399c7ba662d5f9966", + "sha256:16e5f4bf4e603eb1fdd5d8180f1a25f30056f22e55ce51fb3d6ad4ab29f7d96f", + "sha256:188215fc0aafb8e03341995e7c4797860181562380f81ed0a87ff455b70bf1f1", + "sha256:189f652a87e876098bbc67b4da1049afb5f5dfbaa310dd67c594b01c10388db6", + "sha256:1ca0083e80e791cffc6efce7660ad24af66c8d4079d2a750b29001b53ff59ada", + "sha256:1e16bf3e5fc9f44632affb159d30a437bfe286ce9e02754759be5536b169b305", + "sha256:2090f6a85cafc5b2db085124d752757c9d251548cedabe9bd31afe6363e0aff2", + "sha256:20b9b5fbe0b88d0bdef2012ef7dee867f874b72528cf1d08f1d59b0e3850129d", + "sha256:22ae2ebf9b0c69d206c003e2f6a914ea33f0a932d4aa16f236afc049d9958f4a", + "sha256:22f3105d4fb15c8f57ff3959a58fcab6ce36814486500cd7485651230ad4d4ef", + "sha256:23bfd518810af7de1116313ebd9092cb9aa629beb12f6ed631ad53356ed6b86c", + "sha256:27e5fc84ccef8dfaabb09d82b7d179c7cf1a3fbc8a966f8274fcb4ab2eb4cadb", + "sha256:3380252550e372e8511d49481bd836264c009adb826b23fefcc5dd3c69692f60", + "sha256:3702ea6872c5a2a4eeefa6ffd36b042e9773f05b1f37ae3ef7264b1163c2dcf6", + "sha256:37bb93b2178e02b7b618893990941900fd25b6b9ac0fa49931a40aecdf083fe4", + "sha256:3914f5aaa0f36d5d60e8ece6a308ee1c9784cd75ec8151062614657a114c4478", + "sha256:3a37ffb35399029b45c6cc33640a92bef403c9fd388acce75cdc88f58bd19a81", + "sha256:3c8b88a2ccf5493b6c8da9076fb151ba106960a2df90c2633f342f120751a9e7", + "sha256:3e97b5e938051226dc025ec80980c285b053ffb1e25a3db2a3aa3bc046bf7f56", + "sha256:3ec660d19bbc671e3a6443325f07263be452c453ac9e512f5eb935e7d4ac28b3", + "sha256:3efe2c2cb5763f2f1b275ad2bf7a287d3f7ebbef35648a9726e3b69284a4f3d6", + "sha256:483a6aea59cb89904e1ceabd2b47368b5600fb7de78a6e4a2c2987b2d256cf30", + "sha256:4867cafcbc6585e4b678876c489b9273b13e9fff9f6d6d66add5e15d11d926cb", + "sha256:48e171e52d1c4d33888e529b999e5900356b9ae588c2f09a52dcefb158b27506", + "sha256:4a9cb68166a34117d6646c0023c7b759bf197bee5ad4272f420a0141d7eb03a0", + "sha256:4b820514bfc0b98a30e3d85462084779900347e4d49267f747ff54060cc33925", + "sha256:4e18b656c5e844539d506a0a06432274d7bd52a7487e6828c63a63d69185626c", + "sha256:4e9f48f58c2c523d5a06faea47866cd35b32655c46b443f163d08c6d0ddb17d6", + "sha256:50b3a2710631848991d0bf7de077502e8994c804bb805aeb2925a981de58ec2e", + "sha256:55b6d90641869892caa9ca42ff913f7ff1c5ece06474fbd32fb2cf6834726c95", + "sha256:57feec87371dbb3520da6192213c7d6fc892d5589a93db548331954de8248fd2", + "sha256:58130ecf8f7b8112cdb841486404f1282b9c86ccb30d3519faf301b2e5659133", + "sha256:5845c1fd4866bb5dd3125d89b90e57ed3138241540897de748cdf19de8a2fca2", + "sha256:59bfeae4b25ec05b34f1956eaa1cb38032282cd4dfabc5056d0a1ec4d696d3aa", + "sha256:5b48204e8d955c47c55b72779802b219a39acc3ee3d0116d5080c388970b76e3", + "sha256:5c09fcfdccdd0b57867577b719c69e347a436b86cd83747f179dbf0cc0d4c1f3", + "sha256:6180c0ae073bddeb5a97a38c03f30c233e0a4d39cd86166251617d1bbd0af436", + "sha256:682b987361e5fd7a139ed565e30d81fd81e9629acc7d925a205366877d8c8657", + "sha256:6b5d83030255983181005e6cfbac1617ce9746b219bc2aad52201ad121226581", + "sha256:6bb5992037f7a9eff7991ebe4273ea7f51f1c1c511e6a2ce511d0e7bdb754492", + "sha256:73eae06aa53af2ea5270cc066dcaf02cc60d2994bbb2c4ef5764949257d10f43", + "sha256:76f364861c3bfc98cbbcbd402d83454ed9e01a5224bb3a28bf70002a230f73e2", + "sha256:820c661588bd01a0aa62a1283f20d2be4281b086f80dad9e955e690c75fb54a2", + "sha256:82176036e65644a6cc5bd619f65f6f19781e8ec2e5330f51aa9ada7504cc1926", + "sha256:87701f25a2352e5bf7454caa64757642734da9f6b11384c1f9d1a8e699758057", + "sha256:9079dfc6a70abe341f521f78405b8949f96db48da98aeb43f9907f342f627cdc", + "sha256:90f8717cb649eea3504091e640a1b8568faad18bd4b9fcd692853a04475a4b80", + "sha256:957cf8e4b6e123a9eea554fa7ebc85674674b713551de587eb318a2df3e00255", + "sha256:99f826cbf970077383d7de805c0681799491cb939c25450b9b5b3ced03ca99f1", + "sha256:9f636b730f7e8cb19feb87094949ba54ee5357440b9658b2a32a5ce4bce53972", + "sha256:a114d03b938376557927ab23f1e950827c3b893ccb94b62fd95d430fd0e5cf53", + "sha256:a185f876e69897a6f3325c3f19f26a297fa058c5e456bfcff8015e9a27e83ae1", + "sha256:a7a9541cd308eed5e30318430a9c74d2132e9a8cb46b901326272d780bf2d423", + "sha256:aa466da5b15ccea564bdab9c89175c762bc12825f4659c11227f515cee76fa4a", + "sha256:aaed8b0562be4a0876ee3b6946f6869b7bcdb571a5d1496683505944e268b160", + "sha256:ab7c4ceb38d91570a650dba194e1ca87c2b543488fe9309b4212694174fd539c", + "sha256:ac10f4c2b9e770c4e393876e35a7046879d195cd123b4f116d299d442b335bcd", + "sha256:b04772ed465fa3cc947db808fa306d79b43e896beb677a56fb2347ca1a49c1fa", + "sha256:b1c416351ee6271b2f49b56ad7f308072f6f44b37118d69c2cad94f3fa8a40d5", + "sha256:b225d95519a5bf73860323e633a664b0d85ad3d5bede6d30d95b35d4dfe8805b", + "sha256:b2f59caeaf7632cc633b5cf6fc449372b83bbdf0da4ae04d5be36118e46cc0aa", + "sha256:b58c621844d55e71c1b7f7c498ce5aa6985d743a1a59034c57a905b3f153c1ef", + "sha256:bf6bea52ec97e95560af5ae576bdac3aa3aae0b6758c6efa115236d9e07dae44", + "sha256:c08be4f460903e5a9d0f76818db3250f12e9c344e79314d1d570fc69d7f4eae4", + "sha256:c7053d3b0353a8b9de430a4f4b4268ac9a4fb3481af37dfe49825bf45ca24156", + "sha256:c943a53e9186688b45b323602298ab727d8865d8c9ee0b17f8d62d14b56f0753", + "sha256:ce2186a7df133a9c895dea3331ddc5ddad42cdd0d1ea2f0a51e5d161e4762f28", + "sha256:d093be959277cb7dee84b801eb1af388b6ad3ca6a6b6bf1ed7585895789d027d", + "sha256:d094ddec350a2fb899fec68d8353c78233debde9b7d8b4beeafa70825f1c281a", + "sha256:d1a9dd711d0877a1ece3d2e4fea11a8e75741ca21954c919406b44e7cf971304", + "sha256:d569388c381b24671589335a3be6e1d45546c2988c2ebe30fdcada8457a31008", + "sha256:d618649d4e70ac6efcbba75be98b26ef5078faad23592f9b51ca492953012429", + "sha256:d83a047959d38a7ff552ff94be767b7fd79b831ad1cd9920662db05fec24fe72", + "sha256:d8fff389528cad1618fb4b26b95550327495462cd745d879a8c7c2115248e399", + "sha256:da1758c76f50c39a2efd5e9859ce7d776317eb1dd34317c8152ac9251fc574a3", + "sha256:db7457bac39421addd0c8449933ac32d8042aae84a14911a757ae6ca3eef1392", + "sha256:e27bbb6d14416713a8bd7aaa1313c0fc8d44ee48d74497a0ff4c3a1b6ccb5167", + "sha256:e617fb6b0b6953fffd762669610c1c4ffd05632c138d61ac7e14ad187870669c", + "sha256:e9aa71e15d9d9beaad2c6b9319edcdc0a49a43ef5c0a4c8265ca9ee7d6c67774", + "sha256:ec2abea24d98246b94913b76a125e855eb5c434f7c46546046372fe60f666351", + "sha256:f179dee3b863ab1c59580ff60f9d99f632f34ccb38bf67a33ec6b3ecadd0fd76", + "sha256:f4c035da3f544b1882bac24115f3e2e8760f10a0107614fc9839fd232200b875", + "sha256:f67f217af4b1ff66c68a87318012de788dd95fcfeb24cc889011f4e1c7454dfd", + "sha256:f90c822a402cb865e396a504f9fc8173ef34212a342d92e362ca498cad308e28", + "sha256:ff3827aef427c89a25cc96ded1759271a93603aba9fb977a6d264648ebf989db" ], - "markers": "python_version >= '3.7'", - "version": "==6.0.5" + "markers": "python_version >= '3.8'", + "version": "==6.1.0" }, "numpy": { "hashes": [ - "sha256:04494f6ec467ccb5369d1808570ae55f6ed9b5809d7f035059000a37b8d7e86f", - "sha256:0a43f0974d501842866cc83471bdb0116ba0dffdbaac33ec05e6afed5b615238", - "sha256:0e50842b2295ba8414c8c1d9d957083d5dfe9e16828b37de883f51fc53c4016f", - "sha256:0ec84b9ba0654f3b962802edc91424331f423dcf5d5f926676e0150789cb3d95", - "sha256:17067d097ed036636fa79f6a869ac26df7db1ba22039d962422506640314933a", - "sha256:1cde1753efe513705a0c6d28f5884e22bdc30438bf0085c5c486cdaff40cd67a", - "sha256:1e72728e7501a450288fc8e1f9ebc73d90cfd4671ebbd631f3e7857c39bd16f2", - "sha256:2635dbd200c2d6faf2ef9a0d04f0ecc6b13b3cad54f7c67c61155138835515d2", - "sha256:2ce46fd0b8a0c947ae047d222f7136fc4d55538741373107574271bc00e20e8f", - "sha256:34f003cb88b1ba38cb9a9a4a3161c1604973d7f9d5552c38bc2f04f829536609", - "sha256:354f373279768fa5a584bac997de6a6c9bc535c482592d7a813bb0c09be6c76f", - "sha256:38ecb5b0582cd125f67a629072fed6f83562d9dd04d7e03256c9829bdec027ad", - "sha256:3e8e01233d57639b2e30966c63d36fcea099d17c53bf424d77f088b0f4babd86", - "sha256:3f6bed7f840d44c08ebdb73b1825282b801799e325bcbdfa6bc5c370e5aecc65", - "sha256:4554eb96f0fd263041baf16cf0881b3f5dafae7a59b1049acb9540c4d57bc8cb", - "sha256:46e161722e0f619749d1cd892167039015b2c2817296104487cd03ed4a955995", - "sha256:49d9f7d256fbc804391a7f72d4a617302b1afac1112fac19b6c6cec63fe7fe8a", - "sha256:4d2f62e55a4cd9c58c1d9a1c9edaedcd857a73cb6fda875bf79093f9d9086f85", - "sha256:5f64641b42b2429f56ee08b4f427a4d2daf916ec59686061de751a55aafa22e4", - "sha256:63b92c512d9dbcc37f9d81b123dec99fdb318ba38c8059afc78086fe73820275", - "sha256:6d7696c615765091cc5093f76fd1fa069870304beaccfd58b5dcc69e55ef49c1", - "sha256:79e843d186c8fb1b102bef3e2bc35ef81160ffef3194646a7fdd6a73c6b97196", - "sha256:821eedb7165ead9eebdb569986968b541f9908979c2da8a4967ecac4439bae3d", - "sha256:84554fc53daa8f6abf8e8a66e076aff6ece62de68523d9f665f32d2fc50fd66e", - "sha256:8d83bb187fb647643bd56e1ae43f273c7f4dbcdf94550d7938cfc32566756514", - "sha256:903703372d46bce88b6920a0cd86c3ad82dae2dbef157b5fc01b70ea1cfc430f", - "sha256:9416a5c2e92ace094e9f0082c5fd473502c91651fb896bc17690d6fc475128d6", - "sha256:9a1712c015831da583b21c5bfe15e8684137097969c6d22e8316ba66b5baabe4", - "sha256:9c27f0946a3536403efb0e1c28def1ae6730a72cd0d5878db38824855e3afc44", - "sha256:a356364941fb0593bb899a1076b92dfa2029f6f5b8ba88a14fd0984aaf76d0df", - "sha256:a7039a136017eaa92c1848152827e1424701532ca8e8967fe480fe1569dae581", - "sha256:acd3a644e4807e73b4e1867b769fbf1ce8c5d80e7caaef0d90dcdc640dfc9787", - "sha256:ad0c86f3455fbd0de6c31a3056eb822fc939f81b1618f10ff3406971893b62a5", - "sha256:b4c76e3d4c56f145d41b7b6751255feefae92edbc9a61e1758a98204200f30fc", - "sha256:b6f6a8f45d0313db07d6d1d37bd0b112f887e1369758a5419c0370ba915b3871", - "sha256:c5a59996dc61835133b56a32ebe4ef3740ea5bc19b3983ac60cc32be5a665d54", - "sha256:c73aafd1afca80afecb22718f8700b40ac7cab927b8abab3c3e337d70e10e5a2", - "sha256:cee6cc0584f71adefe2c908856ccc98702baf95ff80092e4ca46061538a2ba98", - "sha256:cef04d068f5fb0518a77857953193b6bb94809a806bd0a14983a8f12ada060c9", - "sha256:cf5d1c9e6837f8af9f92b6bd3e86d513cdc11f60fd62185cc49ec7d1aba34864", - "sha256:e61155fae27570692ad1d327e81c6cf27d535a5d7ef97648a17d922224b216de", - "sha256:e7f387600d424f91576af20518334df3d97bc76a300a755f9a8d6e4f5cadd289", - "sha256:ed08d2703b5972ec736451b818c2eb9da80d66c3e84aed1deeb0c345fefe461b", - "sha256:fbd6acc766814ea6443628f4e6751d0da6593dae29c08c0b2606164db026970c", - "sha256:feff59f27338135776f6d4e2ec7aeeac5d5f7a08a83e80869121ef8164b74af9" + "sha256:05b2d4e667895cc55e3ff2b56077e4c8a5604361fc21a042845ea3ad67465aa8", + "sha256:12edb90831ff481f7ef5f6bc6431a9d74dc0e5ff401559a71e5e4611d4f2d466", + "sha256:13311c2db4c5f7609b462bc0f43d3c465424d25c626d95040f073e30f7570e35", + "sha256:13532a088217fa624c99b843eeb54640de23b3414b14aa66d023805eb731066c", + "sha256:13602b3174432a35b16c4cfb5de9a12d229727c3dd47a6ce35111f2ebdf66ff4", + "sha256:1600068c262af1ca9580a527d43dc9d959b0b1d8e56f8a05d830eea39b7c8af6", + "sha256:1b8cde4f11f0a975d1fd59373b32e2f5a562ade7cde4f85b7137f3de8fbb29a0", + "sha256:1c193d0b0238638e6fc5f10f1b074a6993cb13b0b431f64079a509d63d3aa8b7", + "sha256:1ebec5fd716c5a5b3d8dfcc439be82a8407b7b24b230d0ad28a81b61c2f4659a", + "sha256:242b39d00e4944431a3cd2db2f5377e15b5785920421993770cddb89992c3f3a", + "sha256:259ec80d54999cc34cd1eb8ded513cb053c3bf4829152a2e00de2371bd406f5e", + "sha256:2abbf905a0b568706391ec6fa15161fad0fb5d8b68d73c461b3c1bab6064dd62", + "sha256:2cbba4b30bf31ddbe97f1c7205ef976909a93a66bb1583e983adbd155ba72ac2", + "sha256:2ffef621c14ebb0188a8633348504a35c13680d6da93ab5cb86f4e54b7e922b5", + "sha256:30d53720b726ec36a7f88dc873f0eec8447fbc93d93a8f079dfac2629598d6ee", + "sha256:32e16a03138cabe0cb28e1007ee82264296ac0983714094380b408097a418cfe", + "sha256:43cca367bf94a14aca50b89e9bc2061683116cfe864e56740e083392f533ce7a", + "sha256:456e3b11cb79ac9946c822a56346ec80275eaf2950314b249b512896c0d2505e", + "sha256:4d6ec0d4222e8ffdab1744da2560f07856421b367928026fb540e1945f2eeeaf", + "sha256:5006b13a06e0b38d561fab5ccc37581f23c9511879be7693bd33c7cd15ca227c", + "sha256:675c741d4739af2dc20cd6c6a5c4b7355c728167845e3c6b0e824e4e5d36a6c3", + "sha256:6cdb606a7478f9ad91c6283e238544451e3a95f30fb5467fbf715964341a8a86", + "sha256:6d95f286b8244b3649b477ac066c6906fbb2905f8ac19b170e2175d3d799f4df", + "sha256:76322dcdb16fccf2ac56f99048af32259dcc488d9b7e25b51e5eca5147a3fb98", + "sha256:7c1c60328bd964b53f8b835df69ae8198659e2b9302ff9ebb7de4e5a5994db3d", + "sha256:860ec6e63e2c5c2ee5e9121808145c7bf86c96cca9ad396c0bd3e0f2798ccbe2", + "sha256:8e00ea6fc82e8a804433d3e9cedaa1051a1422cb6e443011590c14d2dea59146", + "sha256:9c6c754df29ce6a89ed23afb25550d1c2d5fdb9901d9c67a16e0b16eaf7e2550", + "sha256:a26ae94658d3ba3781d5e103ac07a876b3e9b29db53f68ed7df432fd033358a8", + "sha256:a65acfdb9c6ebb8368490dbafe83c03c7e277b37e6857f0caeadbbc56e12f4fb", + "sha256:a7d80b2e904faa63068ead63107189164ca443b42dd1930299e0d1cb041cec2e", + "sha256:a84498e0d0a1174f2b3ed769b67b656aa5460c92c9554039e11f20a05650f00d", + "sha256:ab4754d432e3ac42d33a269c8567413bdb541689b02d93788af4131018cbf366", + "sha256:ad369ed238b1959dfbade9018a740fb9392c5ac4f9b5173f420bd4f37ba1f7a0", + "sha256:b1d0fcae4f0949f215d4632be684a539859b295e2d0cb14f78ec231915d644db", + "sha256:b42a1a511c81cc78cbc4539675713bbcf9d9c3913386243ceff0e9429ca892fe", + "sha256:bd33f82e95ba7ad632bc57837ee99dba3d7e006536200c4e9124089e1bf42426", + "sha256:bdd407c40483463898b84490770199d5714dcc9dd9b792f6c6caccc523c00952", + "sha256:c6eef7a2dbd0abfb0d9eaf78b73017dbfd0b54051102ff4e6a7b2980d5ac1a03", + "sha256:c82af4b2ddd2ee72d1fc0c6695048d457e00b3582ccde72d8a1c991b808bb20f", + "sha256:d666cb72687559689e9906197e3bec7b736764df6a2e58ee265e360663e9baf7", + "sha256:d7bf0a4f9f15b32b5ba53147369e94296f5fffb783db5aacc1be15b4bf72f43b", + "sha256:d82075752f40c0ddf57e6e02673a17f6cb0f8eb3f587f63ca1eaab5594da5b17", + "sha256:da65fb46d4cbb75cb417cddf6ba5e7582eb7bb0b47db4b99c9fe5787ce5d91f5", + "sha256:e2b49c3c0804e8ecb05d59af8386ec2f74877f7ca8fd9c1e00be2672e4d399b1", + "sha256:e585c8ae871fd38ac50598f4763d73ec5497b0de9a0ab4ef5b69f01c6a046142", + "sha256:e8d3ca0a72dd8846eb6f7dfe8f19088060fcb76931ed592d29128e0219652884", + "sha256:ef444c57d664d35cac4e18c298c47d7b504c66b17c2ea91312e979fcfbdfb08a", + "sha256:f1eb068ead09f4994dec71c24b2844f1e4e4e013b9629f812f292f04bd1510d9", + "sha256:f2ded8d9b6f68cc26f8425eda5d3877b47343e68ca23d0d0846f4d312ecaa445", + "sha256:f751ed0a2f250541e19dfca9f1eafa31a392c71c832b6bb9e113b10d050cb0f1", + "sha256:faa88bc527d0f097abdc2c663cddf37c05a1c2f113716601555249805cf573f1", + "sha256:fc44e3c68ff00fd991b59092a54350e6e4911152682b4782f68070985aa9e648" ], "markers": "python_version == '3.11'", - "version": "==2.0.0" + "version": "==2.1.2" }, "opensearch-py": { "hashes": [ - "sha256:0b7c27e8ed84c03c99558406927b6161f186a72502ca6d0325413d8e5523ba96", - "sha256:b6e78b685dd4e9c016d7a4299cf1de69e299c88322e3f81c716e6e23fe5683c1" + "sha256:5417650eba98a1c7648e502207cebf3a12beab623ffe0ebbf55f9b1b4b6e44e9", + "sha256:67ab76e9373669bc71da417096df59827c08369ac3795d5438c9a8be21cbd759" ], "index": "pypi", - "version": "==2.6.0" + "markers": "python_version >= '3.8' and python_version < '4'", + "version": "==2.7.1" }, "packaging": { "hashes": [ @@ -864,38 +941,51 @@ }, "pandas": { "hashes": [ - "sha256:001910ad31abc7bf06f49dcc903755d2f7f3a9186c0c040b827e522e9cef0863", - "sha256:0ca6377b8fca51815f382bd0b697a0814c8bda55115678cbc94c30aacbb6eff2", - "sha256:0cace394b6ea70c01ca1595f839cf193df35d1575986e484ad35c4aeae7266c1", - "sha256:1cb51fe389360f3b5a4d57dbd2848a5f033350336ca3b340d1c53a1fad33bcad", - "sha256:2925720037f06e89af896c70bca73459d7e6a4be96f9de79e2d440bd499fe0db", - "sha256:3e374f59e440d4ab45ca2fffde54b81ac3834cf5ae2cdfa69c90bc03bde04d76", - "sha256:40ae1dffb3967a52203105a077415a86044a2bea011b5f321c6aa64b379a3f51", - "sha256:43498c0bdb43d55cb162cdc8c06fac328ccb5d2eabe3cadeb3529ae6f0517c32", - "sha256:4abfe0be0d7221be4f12552995e58723c7422c80a659da13ca382697de830c08", - "sha256:58b84b91b0b9f4bafac2a0ac55002280c094dfc6402402332c0913a59654ab2b", - "sha256:640cef9aa381b60e296db324337a554aeeb883ead99dc8f6c18e81a93942f5f4", - "sha256:66b479b0bd07204e37583c191535505410daa8df638fd8e75ae1b383851fe921", - "sha256:696039430f7a562b74fa45f540aca068ea85fa34c244d0deee539cb6d70aa288", - "sha256:6d2123dc9ad6a814bcdea0f099885276b31b24f7edf40f6cdbc0912672e22eee", - "sha256:8635c16bf3d99040fdf3ca3db669a7250ddf49c55dc4aa8fe0ae0fa8d6dcc1f0", - "sha256:873d13d177501a28b2756375d59816c365e42ed8417b41665f346289adc68d24", - "sha256:8e5a0b00e1e56a842f922e7fae8ae4077aee4af0acb5ae3622bd4b4c30aedf99", - "sha256:8e90497254aacacbc4ea6ae5e7a8cd75629d6ad2b30025a4a8b09aa4faf55151", - "sha256:9057e6aa78a584bc93a13f0a9bf7e753a5e9770a30b4d758b8d5f2a62a9433cd", - "sha256:90c6fca2acf139569e74e8781709dccb6fe25940488755716d1d354d6bc58bce", - "sha256:92fd6b027924a7e178ac202cfbe25e53368db90d56872d20ffae94b96c7acc57", - "sha256:9dfde2a0ddef507a631dc9dc4af6a9489d5e2e740e226ad426a05cabfbd7c8ef", - "sha256:9e79019aba43cb4fda9e4d983f8e88ca0373adbb697ae9c6c43093218de28b54", - "sha256:a77e9d1c386196879aa5eb712e77461aaee433e54c68cf253053a73b7e49c33a", - "sha256:c7adfc142dac335d8c1e0dcbd37eb8617eac386596eb9e1a1b77791cf2498238", - "sha256:d187d355ecec3629624fccb01d104da7d7f391db0311145817525281e2804d23", - "sha256:ddf818e4e6c7c6f4f7c8a12709696d193976b591cc7dc50588d3d1a6b5dc8772", - "sha256:e9b79011ff7a0f4b1d6da6a61aa1aa604fb312d6647de5bad20013682d1429ce", - "sha256:eee3a87076c0756de40b05c5e9a6069c035ba43e8dd71c379e68cab2c20f16ad" + "sha256:062309c1b9ea12a50e8ce661145c6aab431b1e99530d3cd60640e255778bd43a", + "sha256:15c0e1e02e93116177d29ff83e8b1619c93ddc9c49083f237d4312337a61165d", + "sha256:1948ddde24197a0f7add2bdc4ca83bf2b1ef84a1bc8ccffd95eda17fd836ecb5", + "sha256:1db71525a1538b30142094edb9adc10be3f3e176748cd7acc2240c2f2e5aa3a4", + "sha256:22a9d949bfc9a502d320aa04e5d02feab689d61da4e7764b62c30b991c42c5f0", + "sha256:29401dbfa9ad77319367d36940cd8a0b3a11aba16063e39632d98b0e931ddf32", + "sha256:31d0ced62d4ea3e231a9f228366919a5ea0b07440d9d4dac345376fd8e1477ea", + "sha256:3508d914817e153ad359d7e069d752cdd736a247c322d932eb89e6bc84217f28", + "sha256:37e0aced3e8f539eccf2e099f65cdb9c8aa85109b0be6e93e2baff94264bdc6f", + "sha256:381175499d3802cde0eabbaf6324cce0c4f5d52ca6f8c377c29ad442f50f6348", + "sha256:38cf8125c40dae9d5acc10fa66af8ea6fdf760b2714ee482ca691fc66e6fcb18", + "sha256:3b71f27954685ee685317063bf13c7709a7ba74fc996b84fc6821c59b0f06468", + "sha256:3fc6873a41186404dad67245896a6e440baacc92f5b716ccd1bc9ed2995ab2c5", + "sha256:4850ba03528b6dd51d6c5d273c46f183f39a9baf3f0143e566b89450965b105e", + "sha256:4f18ba62b61d7e192368b84517265a99b4d7ee8912f8708660fb4a366cc82667", + "sha256:56534ce0746a58afaf7942ba4863e0ef81c9c50d3f0ae93e9497d6a41a057645", + "sha256:59ef3764d0fe818125a5097d2ae867ca3fa64df032331b7e0917cf5d7bf66b13", + "sha256:5dbca4c1acd72e8eeef4753eeca07de9b1db4f398669d5994086f788a5d7cc30", + "sha256:5de54125a92bb4d1c051c0659e6fcb75256bf799a732a87184e5ea503965bce3", + "sha256:61c5ad4043f791b61dd4752191d9f07f0ae412515d59ba8f005832a532f8736d", + "sha256:6374c452ff3ec675a8f46fd9ab25c4ad0ba590b71cf0656f8b6daa5202bca3fb", + "sha256:63cc132e40a2e084cf01adf0775b15ac515ba905d7dcca47e9a251819c575ef3", + "sha256:66108071e1b935240e74525006034333f98bcdb87ea116de573a6a0dccb6c039", + "sha256:6dfcb5ee8d4d50c06a51c2fffa6cff6272098ad6540aed1a76d15fb9318194d8", + "sha256:7c2875855b0ff77b2a64a0365e24455d9990730d6431b9e0ee18ad8acee13dbd", + "sha256:7eee9e7cea6adf3e3d24e304ac6b8300646e2a5d1cd3a3c2abed9101b0846761", + "sha256:800250ecdadb6d9c78eae4990da62743b857b470883fa27f652db8bdde7f6659", + "sha256:86976a1c5b25ae3f8ccae3a5306e443569ee3c3faf444dfd0f41cda24667ad57", + "sha256:8cd6d7cc958a3910f934ea8dbdf17b2364827bb4dafc38ce6eef6bb3d65ff09c", + "sha256:99df71520d25fade9db7c1076ac94eb994f4d2673ef2aa2e86ee039b6746d20c", + "sha256:a5a1595fe639f5988ba6a8e5bc9649af3baf26df3998a0abe56c02609392e0a4", + "sha256:ad5b65698ab28ed8d7f18790a0dc58005c7629f227be9ecc1072aa74c0c1d43a", + "sha256:b1d432e8d08679a40e2a6d8b2f9770a5c21793a6f9f47fdd52c5ce1948a5a8a9", + "sha256:b8661b0238a69d7aafe156b7fa86c44b881387509653fdf857bebc5e4008ad42", + "sha256:ba96630bc17c875161df3818780af30e43be9b166ce51c9a18c1feae342906c2", + "sha256:bc6b93f9b966093cb0fd62ff1a7e4c09e6d546ad7c1de191767baffc57628f39", + "sha256:c124333816c3a9b03fbeef3a9f230ba9a737e9e5bb4060aa2107a86cc0a497fc", + "sha256:cd8d0c3be0515c12fed0bdbae072551c8b54b7192c7b1fda0ba56059a0179698", + "sha256:d9c45366def9a3dd85a6454c0e7908f2b3b8e9c138f5dc38fed7ce720d8453ed", + "sha256:f00d1345d84d8c86a63e476bb4955e46458b304b9575dcf71102b5c705320015", + "sha256:f3a255b2c19987fbbe62a9dfd6cff7ff2aa9ccab3fc75218fd4b7530f01efa24", + "sha256:fffb8ae78d8af97f849404f21411c95062db1496aeb3e56f146f0355c9989319" ], "markers": "python_version >= '3.9'", - "version": "==2.2.2" + "version": "==2.2.3" }, "pika": { "hashes": [ @@ -915,19 +1005,123 @@ }, "prometheus-client": { "hashes": [ - "sha256:287629d00b147a32dcb2be0b9df905da599b2d82f80377083ec8463309a4bb89", - "sha256:cde524a85bce83ca359cc837f28b8c0db5cac7aa653a588fd7e84ba061c329e7" + "sha256:4fa6b4dd0ac16d58bb587c04b1caae65b8c5043e85f778f42f5f632f6af2e166", + "sha256:96c83c606b71ff2b0a433c98889d275f51ffec6c5e267de37c7a2b5c9aa9233e" ], "markers": "python_version >= '3.8'", - "version": "==0.20.0" + "version": "==0.21.0" }, "prometheus-flask-exporter": { "hashes": [ - "sha256:7a026b4fdd54ebeddb77589333efe3a1ec43c7c717468825b0b3e9b6c33f7e9e", - "sha256:e4e6beb1b8e1e164da6d70fe1edefc95ef184f113b5047f66f4b7262233da9c0" + "sha256:587c770a1061e93d72c5cbcdefbd7b633fb764e39dffd7dd16932c9124559244", + "sha256:ab49b2c40b57cd35cd51e91e59b3c306b3754477095c4f3cf679034c5122398c" ], "index": "pypi", - "version": "==0.23.0" + "version": "==0.23.1" + }, + "propcache": { + "hashes": [ + "sha256:00181262b17e517df2cd85656fcd6b4e70946fe62cd625b9d74ac9977b64d8d9", + "sha256:0e53cb83fdd61cbd67202735e6a6687a7b491c8742dfc39c9e01e80354956763", + "sha256:1235c01ddaa80da8235741e80815ce381c5267f96cc49b1477fdcf8c047ef325", + "sha256:140fbf08ab3588b3468932974a9331aff43c0ab8a2ec2c608b6d7d1756dbb6cb", + "sha256:191db28dc6dcd29d1a3e063c3be0b40688ed76434622c53a284e5427565bbd9b", + "sha256:1e41d67757ff4fbc8ef2af99b338bfb955010444b92929e9e55a6d4dcc3c4f09", + "sha256:1ec43d76b9677637a89d6ab86e1fef70d739217fefa208c65352ecf0282be957", + "sha256:20a617c776f520c3875cf4511e0d1db847a076d720714ae35ffe0df3e440be68", + "sha256:218db2a3c297a3768c11a34812e63b3ac1c3234c3a086def9c0fee50d35add1f", + "sha256:22aa8f2272d81d9317ff5756bb108021a056805ce63dd3630e27d042c8092798", + "sha256:25a1f88b471b3bc911d18b935ecb7115dff3a192b6fef46f0bfaf71ff4f12418", + "sha256:25c8d773a62ce0451b020c7b29a35cfbc05de8b291163a7a0f3b7904f27253e6", + "sha256:2a60ad3e2553a74168d275a0ef35e8c0a965448ffbc3b300ab3a5bb9956c2162", + "sha256:2a66df3d4992bc1d725b9aa803e8c5a66c010c65c741ad901e260ece77f58d2f", + "sha256:2ccc28197af5313706511fab3a8b66dcd6da067a1331372c82ea1cb74285e036", + "sha256:2e900bad2a8456d00a113cad8c13343f3b1f327534e3589acc2219729237a2e8", + "sha256:2ee7606193fb267be4b2e3b32714f2d58cad27217638db98a60f9efb5efeccc2", + "sha256:33ac8f098df0585c0b53009f039dfd913b38c1d2edafed0cedcc0c32a05aa110", + "sha256:3444cdba6628accf384e349014084b1cacd866fbb88433cd9d279d90a54e0b23", + "sha256:363ea8cd3c5cb6679f1c2f5f1f9669587361c062e4899fce56758efa928728f8", + "sha256:375a12d7556d462dc64d70475a9ee5982465fbb3d2b364f16b86ba9135793638", + "sha256:388f3217649d6d59292b722d940d4d2e1e6a7003259eb835724092a1cca0203a", + "sha256:3947483a381259c06921612550867b37d22e1df6d6d7e8361264b6d037595f44", + "sha256:39e104da444a34830751715f45ef9fc537475ba21b7f1f5b0f4d71a3b60d7fe2", + "sha256:3c997f8c44ec9b9b0bcbf2d422cc00a1d9b9c681f56efa6ca149a941e5560da2", + "sha256:3dfafb44f7bb35c0c06eda6b2ab4bfd58f02729e7c4045e179f9a861b07c9850", + "sha256:3ebbcf2a07621f29638799828b8d8668c421bfb94c6cb04269130d8de4fb7136", + "sha256:3f88a4095e913f98988f5b338c1d4d5d07dbb0b6bad19892fd447484e483ba6b", + "sha256:439e76255daa0f8151d3cb325f6dd4a3e93043e6403e6491813bcaaaa8733887", + "sha256:4569158070180c3855e9c0791c56be3ceeb192defa2cdf6a3f39e54319e56b89", + "sha256:466c219deee4536fbc83c08d09115249db301550625c7fef1c5563a584c9bc87", + "sha256:4a9d9b4d0a9b38d1c391bb4ad24aa65f306c6f01b512e10a8a34a2dc5675d348", + "sha256:4c7dde9e533c0a49d802b4f3f218fa9ad0a1ce21f2c2eb80d5216565202acab4", + "sha256:53d1bd3f979ed529f0805dd35ddaca330f80a9a6d90bc0121d2ff398f8ed8861", + "sha256:55346705687dbd7ef0d77883ab4f6fabc48232f587925bdaf95219bae072491e", + "sha256:56295eb1e5f3aecd516d91b00cfd8bf3a13991de5a479df9e27dd569ea23959c", + "sha256:56bb5c98f058a41bb58eead194b4db8c05b088c93d94d5161728515bd52b052b", + "sha256:5a5b3bb545ead161be780ee85a2b54fdf7092815995661947812dde94a40f6fb", + "sha256:5f2564ec89058ee7c7989a7b719115bdfe2a2fb8e7a4543b8d1c0cc4cf6478c1", + "sha256:608cce1da6f2672a56b24a015b42db4ac612ee709f3d29f27a00c943d9e851de", + "sha256:63f13bf09cc3336eb04a837490b8f332e0db41da66995c9fd1ba04552e516354", + "sha256:662dd62358bdeaca0aee5761de8727cfd6861432e3bb828dc2a693aa0471a563", + "sha256:676135dcf3262c9c5081cc8f19ad55c8a64e3f7282a21266d05544450bffc3a5", + "sha256:67aeb72e0f482709991aa91345a831d0b707d16b0257e8ef88a2ad246a7280bf", + "sha256:67b69535c870670c9f9b14a75d28baa32221d06f6b6fa6f77a0a13c5a7b0a5b9", + "sha256:682a7c79a2fbf40f5dbb1eb6bfe2cd865376deeac65acf9beb607505dced9e12", + "sha256:6994984550eaf25dd7fc7bd1b700ff45c894149341725bb4edc67f0ffa94efa4", + "sha256:69d3a98eebae99a420d4b28756c8ce6ea5a29291baf2dc9ff9414b42676f61d5", + "sha256:6e2e54267980349b723cff366d1e29b138b9a60fa376664a157a342689553f71", + "sha256:73e4b40ea0eda421b115248d7e79b59214411109a5bc47d0d48e4c73e3b8fcf9", + "sha256:74acd6e291f885678631b7ebc85d2d4aec458dd849b8c841b57ef04047833bed", + "sha256:7665f04d0c7f26ff8bb534e1c65068409bf4687aa2534faf7104d7182debb336", + "sha256:7735e82e3498c27bcb2d17cb65d62c14f1100b71723b68362872bca7d0913d90", + "sha256:77a86c261679ea5f3896ec060be9dc8e365788248cc1e049632a1be682442063", + "sha256:7cf18abf9764746b9c8704774d8b06714bcb0a63641518a3a89c7f85cc02c2ad", + "sha256:83928404adf8fb3d26793665633ea79b7361efa0287dfbd372a7e74311d51ee6", + "sha256:8e40876731f99b6f3c897b66b803c9e1c07a989b366c6b5b475fafd1f7ba3fb8", + "sha256:8f188cfcc64fb1266f4684206c9de0e80f54622c3f22a910cbd200478aeae61e", + "sha256:91997d9cb4a325b60d4e3f20967f8eb08dfcb32b22554d5ef78e6fd1dda743a2", + "sha256:91ee8fc02ca52e24bcb77b234f22afc03288e1dafbb1f88fe24db308910c4ac7", + "sha256:92fe151145a990c22cbccf9ae15cae8ae9eddabfc949a219c9f667877e40853d", + "sha256:945db8ee295d3af9dbdbb698cce9bbc5c59b5c3fe328bbc4387f59a8a35f998d", + "sha256:9517d5e9e0731957468c29dbfd0f976736a0e55afaea843726e887f36fe017df", + "sha256:952e0d9d07609d9c5be361f33b0d6d650cd2bae393aabb11d9b719364521984b", + "sha256:97a58a28bcf63284e8b4d7b460cbee1edaab24634e82059c7b8c09e65284f178", + "sha256:97e48e8875e6c13909c800fa344cd54cc4b2b0db1d5f911f840458a500fde2c2", + "sha256:9e0f07b42d2a50c7dd2d8675d50f7343d998c64008f1da5fef888396b7f84630", + "sha256:a3dc1a4b165283bd865e8f8cb5f0c64c05001e0718ed06250d8cac9bec115b48", + "sha256:a3ebe9a75be7ab0b7da2464a77bb27febcb4fab46a34f9288f39d74833db7f61", + "sha256:a64e32f8bd94c105cc27f42d3b658902b5bcc947ece3c8fe7bc1b05982f60e89", + "sha256:a6ed8db0a556343d566a5c124ee483ae113acc9a557a807d439bcecc44e7dfbb", + "sha256:ad9c9b99b05f163109466638bd30ada1722abb01bbb85c739c50b6dc11f92dc3", + "sha256:b33d7a286c0dc1a15f5fc864cc48ae92a846df287ceac2dd499926c3801054a6", + "sha256:bc092ba439d91df90aea38168e11f75c655880c12782facf5cf9c00f3d42b562", + "sha256:c436130cc779806bdf5d5fae0d848713105472b8566b75ff70048c47d3961c5b", + "sha256:c5869b8fd70b81835a6f187c5fdbe67917a04d7e52b6e7cc4e5fe39d55c39d58", + "sha256:c5ecca8f9bab618340c8e848d340baf68bcd8ad90a8ecd7a4524a81c1764b3db", + "sha256:cfac69017ef97db2438efb854edf24f5a29fd09a536ff3a992b75990720cdc99", + "sha256:d2f0d0f976985f85dfb5f3d685697ef769faa6b71993b46b295cdbbd6be8cc37", + "sha256:d5bed7f9805cc29c780f3aee05de3262ee7ce1f47083cfe9f77471e9d6777e83", + "sha256:d6a21ef516d36909931a2967621eecb256018aeb11fc48656e3257e73e2e247a", + "sha256:d9b6ddac6408194e934002a69bcaadbc88c10b5f38fb9307779d1c629181815d", + "sha256:db47514ffdbd91ccdc7e6f8407aac4ee94cc871b15b577c1c324236b013ddd04", + "sha256:df81779732feb9d01e5d513fad0122efb3d53bbc75f61b2a4f29a020bc985e70", + "sha256:e4a91d44379f45f5e540971d41e4626dacd7f01004826a18cb048e7da7e96544", + "sha256:e63e3e1e0271f374ed489ff5ee73d4b6e7c60710e1f76af5f0e1a6117cd26394", + "sha256:e70fac33e8b4ac63dfc4c956fd7d85a0b1139adcfc0d964ce288b7c527537fea", + "sha256:ecddc221a077a8132cf7c747d5352a15ed763b674c0448d811f408bf803d9ad7", + "sha256:f45eec587dafd4b2d41ac189c2156461ebd0c1082d2fe7013571598abb8505d1", + "sha256:f52a68c21363c45297aca15561812d542f8fc683c85201df0bebe209e349f793", + "sha256:f571aea50ba5623c308aa146eb650eebf7dbe0fd8c5d946e28343cb3b5aad577", + "sha256:f60f0ac7005b9f5a6091009b09a419ace1610e163fa5deaba5ce3484341840e7", + "sha256:f6475a1b2ecb310c98c28d271a30df74f9dd436ee46d09236a6b750a7599ce57", + "sha256:f6d5749fdd33d90e34c2efb174c7e236829147a2713334d708746e94c4bde40d", + "sha256:f902804113e032e2cdf8c71015651c97af6418363bea8d78dc0911d56c335032", + "sha256:fa1076244f54bb76e65e22cb6910365779d5c3d71d1f18b275f1dfc7b0d71b4d", + "sha256:fc2db02409338bf36590aa985a461b2c96fce91f8e7e0f14c50c5fcc4f229016", + "sha256:ffcad6c564fe6b9b8916c1aefbb37a362deebf9394bd2974e9d84232e3e08504" + ], + "markers": "python_version >= '3.8'", + "version": "==0.2.0" }, "pycparser": { "hashes": [ @@ -939,127 +1133,138 @@ }, "pydantic": { "hashes": [ - "sha256:0c84efd9548d545f63ac0060c1e4d39bb9b14db8b3c0652338aecc07b5adec52", - "sha256:ee8538d41ccb9c0a9ad3e0e5f07bf15ed8015b481ced539a1759d8cc89ae90d0" + "sha256:d155cef71265d1e9807ed1c32b4c8deec042a44a50a4188b25ac67ecd81a9c0f", + "sha256:f048cec7b26778210e28a0459867920654d48e5e62db0958433636cde4254f12" ], "markers": "python_version >= '3.8'", - "version": "==2.7.4" + "version": "==2.9.2" }, "pydantic-core": { "hashes": [ - "sha256:01dd777215e2aa86dfd664daed5957704b769e726626393438f9c87690ce78c3", - "sha256:0eb2a4f660fcd8e2b1c90ad566db2b98d7f3f4717c64fe0a83e0adb39766d5b8", - "sha256:0fbbdc827fe5e42e4d196c746b890b3d72876bdbf160b0eafe9f0334525119c8", - "sha256:123c3cec203e3f5ac7b000bd82235f1a3eced8665b63d18be751f115588fea30", - "sha256:14601cdb733d741b8958224030e2bfe21a4a881fb3dd6fbb21f071cabd48fa0a", - "sha256:18f469a3d2a2fdafe99296a87e8a4c37748b5080a26b806a707f25a902c040a8", - "sha256:19894b95aacfa98e7cb093cd7881a0c76f55731efad31073db4521e2b6ff5b7d", - "sha256:1b4de2e51bbcb61fdebd0ab86ef28062704f62c82bbf4addc4e37fa4b00b7cbc", - "sha256:1d886dc848e60cb7666f771e406acae54ab279b9f1e4143babc9c2258213daa2", - "sha256:1f4d26ceb5eb9eed4af91bebeae4b06c3fb28966ca3a8fb765208cf6b51102ab", - "sha256:21a5e440dbe315ab9825fcd459b8814bb92b27c974cbc23c3e8baa2b76890077", - "sha256:293afe532740370aba8c060882f7d26cfd00c94cae32fd2e212a3a6e3b7bc15e", - "sha256:2f5966897e5461f818e136b8451d0551a2e77259eb0f73a837027b47dc95dab9", - "sha256:2fd41f6eff4c20778d717af1cc50eca52f5afe7805ee530a4fbd0bae284f16e9", - "sha256:2fdf2156aa3d017fddf8aea5adfba9f777db1d6022d392b682d2a8329e087cef", - "sha256:3c40d4eaad41f78e3bbda31b89edc46a3f3dc6e171bf0ecf097ff7a0ffff7cb1", - "sha256:43d447dd2ae072a0065389092a231283f62d960030ecd27565672bd40746c507", - "sha256:44a688331d4a4e2129140a8118479443bd6f1905231138971372fcde37e43528", - "sha256:44c7486a4228413c317952e9d89598bcdfb06399735e49e0f8df643e1ccd0558", - "sha256:44cd83ab6a51da80fb5adbd9560e26018e2ac7826f9626bc06ca3dc074cd198b", - "sha256:46387e38bd641b3ee5ce247563b60c5ca098da9c56c75c157a05eaa0933ed154", - "sha256:4701b19f7e3a06ea655513f7938de6f108123bf7c86bbebb1196eb9bd35cf724", - "sha256:4748321b5078216070b151d5271ef3e7cc905ab170bbfd27d5c83ee3ec436695", - "sha256:4b06beb3b3f1479d32befd1f3079cc47b34fa2da62457cdf6c963393340b56e9", - "sha256:4d0dcc59664fcb8974b356fe0a18a672d6d7cf9f54746c05f43275fc48636851", - "sha256:4e99bc050fe65c450344421017f98298a97cefc18c53bb2f7b3531eb39bc7805", - "sha256:509daade3b8649f80d4e5ff21aa5673e4ebe58590b25fe42fac5f0f52c6f034a", - "sha256:51991a89639a912c17bef4b45c87bd83593aee0437d8102556af4885811d59f5", - "sha256:53db086f9f6ab2b4061958d9c276d1dbe3690e8dd727d6abf2321d6cce37fa94", - "sha256:564d7922e4b13a16b98772441879fcdcbe82ff50daa622d681dd682175ea918c", - "sha256:574d92eac874f7f4db0ca653514d823a0d22e2354359d0759e3f6a406db5d55d", - "sha256:578e24f761f3b425834f297b9935e1ce2e30f51400964ce4801002435a1b41ef", - "sha256:59ff3e89f4eaf14050c8022011862df275b552caef8082e37b542b066ce1ff26", - "sha256:5f09baa656c904807e832cf9cce799c6460c450c4ad80803517032da0cd062e2", - "sha256:6891a2ae0e8692679c07728819b6e2b822fb30ca7445f67bbf6509b25a96332c", - "sha256:6a750aec7bf431517a9fd78cb93c97b9b0c496090fee84a47a0d23668976b4b0", - "sha256:6f5c4d41b2771c730ea1c34e458e781b18cc668d194958e0112455fff4e402b2", - "sha256:77450e6d20016ec41f43ca4a6c63e9fdde03f0ae3fe90e7c27bdbeaece8b1ed4", - "sha256:81b5efb2f126454586d0f40c4d834010979cb80785173d1586df845a632e4e6d", - "sha256:823be1deb01793da05ecb0484d6c9e20baebb39bd42b5d72636ae9cf8350dbd2", - "sha256:834b5230b5dfc0c1ec37b2fda433b271cbbc0e507560b5d1588e2cc1148cf1ce", - "sha256:847a35c4d58721c5dc3dba599878ebbdfd96784f3fb8bb2c356e123bdcd73f34", - "sha256:86110d7e1907ab36691f80b33eb2da87d780f4739ae773e5fc83fb272f88825f", - "sha256:8951eee36c57cd128f779e641e21eb40bc5073eb28b2d23f33eb0ef14ffb3f5d", - "sha256:8a7164fe2005d03c64fd3b85649891cd4953a8de53107940bf272500ba8a788b", - "sha256:8b8bab4c97248095ae0c4455b5a1cd1cdd96e4e4769306ab19dda135ea4cdb07", - "sha256:90afc12421df2b1b4dcc975f814e21bc1754640d502a2fbcc6d41e77af5ec312", - "sha256:938cb21650855054dc54dfd9120a851c974f95450f00683399006aa6e8abb057", - "sha256:942ba11e7dfb66dc70f9ae66b33452f51ac7bb90676da39a7345e99ffb55402d", - "sha256:972658f4a72d02b8abfa2581d92d59f59897d2e9f7e708fdabe922f9087773af", - "sha256:97736815b9cc893b2b7f663628e63f436018b75f44854c8027040e05230eeddb", - "sha256:98906207f29bc2c459ff64fa007afd10a8c8ac080f7e4d5beff4c97086a3dabd", - "sha256:99457f184ad90235cfe8461c4d70ab7dd2680e28821c29eca00252ba90308c78", - "sha256:a0d829524aaefdebccb869eed855e2d04c21d2d7479b6cada7ace5448416597b", - "sha256:a2fdd81edd64342c85ac7cf2753ccae0b79bf2dfa063785503cb85a7d3593223", - "sha256:a55b5b16c839df1070bc113c1f7f94a0af4433fcfa1b41799ce7606e5c79ce0a", - "sha256:a642295cd0c8df1b86fc3dced1d067874c353a188dc8e0f744626d49e9aa51c4", - "sha256:ab86ce7c8f9bea87b9d12c7f0af71102acbf5ecbc66c17796cff45dae54ef9a5", - "sha256:abc267fa9837245cc28ea6929f19fa335f3dc330a35d2e45509b6566dc18be23", - "sha256:ae1d6df168efb88d7d522664693607b80b4080be6750c913eefb77e34c12c71a", - "sha256:b2ebef0e0b4454320274f5e83a41844c63438fdc874ea40a8b5b4ecb7693f1c4", - "sha256:b48ece5bde2e768197a2d0f6e925f9d7e3e826f0ad2271120f8144a9db18d5c8", - "sha256:b7cdf28938ac6b8b49ae5e92f2735056a7ba99c9b110a474473fd71185c1af5d", - "sha256:bb4462bd43c2460774914b8525f79b00f8f407c945d50881568f294c1d9b4443", - "sha256:bc4ff9805858bd54d1a20efff925ccd89c9d2e7cf4986144b30802bf78091c3e", - "sha256:c1322d7dd74713dcc157a2b7898a564ab091ca6c58302d5c7b4c07296e3fd00f", - "sha256:c67598100338d5d985db1b3d21f3619ef392e185e71b8d52bceacc4a7771ea7e", - "sha256:ca26a1e73c48cfc54c4a76ff78df3727b9d9f4ccc8dbee4ae3f73306a591676d", - "sha256:d323a01da91851a4f17bf592faf46149c9169d68430b3146dcba2bb5e5719abc", - "sha256:dc1803ac5c32ec324c5261c7209e8f8ce88e83254c4e1aebdc8b0a39f9ddb443", - "sha256:e00a3f196329e08e43d99b79b286d60ce46bed10f2280d25a1718399457e06be", - "sha256:e85637bc8fe81ddb73fda9e56bab24560bdddfa98aa64f87aaa4e4b6730c23d2", - "sha256:e858ac0a25074ba4bce653f9b5d0a85b7456eaddadc0ce82d3878c22489fa4ee", - "sha256:eae237477a873ab46e8dd748e515c72c0c804fb380fbe6c85533c7de51f23a8f", - "sha256:ebef0dd9bf9b812bf75bda96743f2a6c5734a02092ae7f721c048d156d5fabae", - "sha256:ec3beeada09ff865c344ff3bc2f427f5e6c26401cc6113d77e372c3fdac73864", - "sha256:f76d0ad001edd426b92233d45c746fd08f467d56100fd8f30e9ace4b005266e4", - "sha256:f85d05aa0918283cf29a30b547b4df2fbb56b45b135f9e35b6807cb28bc47951", - "sha256:f9899c94762343f2cc2fc64c13e7cae4c3cc65cdfc87dd810a31654c9b7358cc" + "sha256:0a7df63886be5e270da67e0966cf4afbae86069501d35c8c1b3b6c168f42cb36", + "sha256:0cb3da3fd1b6a5d0279a01877713dbda118a2a4fc6f0d821a57da2e464793f05", + "sha256:0dbd8dbed2085ed23b5c04afa29d8fd2771674223135dc9bc937f3c09284d071", + "sha256:0dff76e0602ca7d4cdaacc1ac4c005e0ce0dcfe095d5b5259163a80d3a10d327", + "sha256:1278e0d324f6908e872730c9102b0112477a7f7cf88b308e4fc36ce1bdb6d58c", + "sha256:128585782e5bfa515c590ccee4b727fb76925dd04a98864182b22e89a4e6ed36", + "sha256:1498bec4c05c9c787bde9125cfdcc63a41004ff167f495063191b863399b1a29", + "sha256:19442362866a753485ba5e4be408964644dd6a09123d9416c54cd49171f50744", + "sha256:1b84d168f6c48fabd1f2027a3d1bdfe62f92cade1fb273a5d68e621da0e44e6d", + "sha256:1e90d2e3bd2c3863d48525d297cd143fe541be8bbf6f579504b9712cb6b643ec", + "sha256:20152074317d9bed6b7a95ade3b7d6054845d70584216160860425f4fbd5ee9e", + "sha256:216f9b2d7713eb98cb83c80b9c794de1f6b7e3145eef40400c62e86cee5f4e1e", + "sha256:233710f069d251feb12a56da21e14cca67994eab08362207785cf8c598e74577", + "sha256:255a8ef062cbf6674450e668482456abac99a5583bbafb73f9ad469540a3a232", + "sha256:2584f7cf844ac4d970fba483a717dbe10c1c1c96a969bf65d61ffe94df1b2863", + "sha256:2971bb5ffe72cc0f555c13e19b23c85b654dd2a8f7ab493c262071377bfce9f6", + "sha256:29d2c342c4bc01b88402d60189f3df065fb0dda3654744d5a165a5288a657368", + "sha256:2e203fdf807ac7e12ab59ca2bfcabb38c7cf0b33c41efeb00f8e5da1d86af480", + "sha256:33e3d65a85a2a4a0dc3b092b938a4062b1a05f3a9abde65ea93b233bca0e03f2", + "sha256:374a5e5049eda9e0a44c696c7ade3ff355f06b1fe0bb945ea3cac2bc336478a2", + "sha256:37b0fe330e4a58d3c58b24d91d1eb102aeec675a3db4c292ec3928ecd892a9a6", + "sha256:3d5639516376dce1940ea36edf408c554475369f5da2abd45d44621cb616f769", + "sha256:42c6dcb030aefb668a2b7009c85b27f90e51e6a3b4d5c9bc4c57631292015b0d", + "sha256:4a7cd62e831afe623fbb7aabbb4fe583212115b3ef38a9f6b71869ba644624a2", + "sha256:4ba762ed58e8d68657fc1281e9bb72e1c3e79cc5d464be146e260c541ec12d84", + "sha256:4fc714bdbfb534f94034efaa6eadd74e5b93c8fa6315565a222f7b6f42ca1166", + "sha256:4ffa2ebd4c8530079140dd2d7f794a9d9a73cbb8e9d59ffe24c63436efa8f271", + "sha256:5a1504ad17ba4210df3a045132a7baeeba5a200e930f57512ee02909fc5c4cb5", + "sha256:5c364564d17da23db1106787675fc7af45f2f7b58b4173bfdd105564e132e6fb", + "sha256:5e11661ce0fd30a6790e8bcdf263b9ec5988e95e63cf901972107efc49218b13", + "sha256:5f54b118ce5de9ac21c363d9b3caa6c800341e8c47a508787e5868c6b79c9323", + "sha256:5f5ff8d839f4566a474a969508fe1c5e59c31c80d9e140566f9a37bba7b8d556", + "sha256:61817945f2fe7d166e75fbfb28004034b48e44878177fc54d81688e7b85a3665", + "sha256:624e278a7d29b6445e4e813af92af37820fafb6dcc55c012c834f9e26f9aaaef", + "sha256:63e46b3169866bd62849936de036f901a9356e36376079b05efa83caeaa02ceb", + "sha256:6531b7ca5f951d663c339002e91aaebda765ec7d61b7d1e3991051906ddde119", + "sha256:68665f4c17edcceecc112dfed5dbe6f92261fb9d6054b47d01bf6371a6196126", + "sha256:696dd8d674d6ce621ab9d45b205df149399e4bb9aa34102c970b721554828510", + "sha256:6f783e0ec4803c787bcea93e13e9932edab72068f68ecffdf86a99fd5918878b", + "sha256:723314c1d51722ab28bfcd5240d858512ffd3116449c557a1336cbe3919beb87", + "sha256:74b9127ffea03643e998e0c5ad9bd3811d3dac8c676e47db17b0ee7c3c3bf35f", + "sha256:7530e201d10d7d14abce4fb54cfe5b94a0aefc87da539d0346a484ead376c3cc", + "sha256:77733e3892bb0a7fa797826361ce8a9184d25c8dffaec60b7ffe928153680ba8", + "sha256:78ddaaa81421a29574a682b3179d4cf9e6d405a09b99d93ddcf7e5239c742e21", + "sha256:7c9129eb40958b3d4500fa2467e6a83356b3b61bfff1b414c7361d9220f9ae8f", + "sha256:7d32706badfe136888bdea71c0def994644e09fff0bfe47441deaed8e96fdbc6", + "sha256:81965a16b675b35e1d09dd14df53f190f9129c0202356ed44ab2728b1c905658", + "sha256:8394d940e5d400d04cad4f75c0598665cbb81aecefaca82ca85bd28264af7f9b", + "sha256:86d2f57d3e1379a9525c5ab067b27dbb8a0642fb5d454e17a9ac434f9ce523e3", + "sha256:883a91b5dd7d26492ff2f04f40fbb652de40fcc0afe07e8129e8ae779c2110eb", + "sha256:88ad334a15b32a791ea935af224b9de1bf99bcd62fabf745d5f3442199d86d59", + "sha256:9261d3ce84fa1d38ed649c3638feefeae23d32ba9182963e465d58d62203bd24", + "sha256:97df63000f4fea395b2824da80e169731088656d1818a11b95f3b173747b6cd9", + "sha256:98d134c954828488b153d88ba1f34e14259284f256180ce659e8d83e9c05eaa3", + "sha256:996a38a83508c54c78a5f41456b0103c30508fed9abcad0a59b876d7398f25fd", + "sha256:9a5bce9d23aac8f0cf0836ecfc033896aa8443b501c58d0602dbfd5bd5b37753", + "sha256:9a6b5099eeec78827553827f4c6b8615978bb4b6a88e5d9b93eddf8bb6790f55", + "sha256:9d18368b137c6295db49ce7218b1a9ba15c5bc254c96d7c9f9e924a9bc7825ad", + "sha256:a4fa4fc04dff799089689f4fd502ce7d59de529fc2f40a2c8836886c03e0175a", + "sha256:a5c7ba8ffb6d6f8f2ab08743be203654bb1aaa8c9dcb09f82ddd34eadb695605", + "sha256:aea443fffa9fbe3af1a9ba721a87f926fe548d32cab71d188a6ede77d0ff244e", + "sha256:b10bd51f823d891193d4717448fab065733958bdb6a6b351967bd349d48d5c9b", + "sha256:ba1a0996f6c2773bd83e63f18914c1de3c9dd26d55f4ac302a7efe93fb8e7433", + "sha256:bb2802e667b7051a1bebbfe93684841cc9351004e2badbd6411bf357ab8d5ac8", + "sha256:cfdd16ab5e59fc31b5e906d1a3f666571abc367598e3e02c83403acabc092e07", + "sha256:d06b0c8da4f16d1d1e352134427cb194a0a6e19ad5db9161bf32b2113409e728", + "sha256:d0776dea117cf5272382634bd2a5c1b6eb16767c223c6a5317cd3e2a757c61a0", + "sha256:d18ca8148bebe1b0a382a27a8ee60350091a6ddaf475fa05ef50dc35b5df6327", + "sha256:d4488a93b071c04dc20f5cecc3631fc78b9789dd72483ba15d423b5b3689b555", + "sha256:d5f7a395a8cf1621939692dba2a6b6a830efa6b3cee787d82c7de1ad2930de64", + "sha256:d7a80d21d613eec45e3d41eb22f8f94ddc758a6c4720842dc74c0581f54993d6", + "sha256:d97683ddee4723ae8c95d1eddac7c192e8c552da0c73a925a89fa8649bf13eea", + "sha256:dcedcd19a557e182628afa1d553c3895a9f825b936415d0dbd3cd0bbcfd29b4b", + "sha256:de6d1d1b9e5101508cb37ab0d972357cac5235f5c6533d1071964c47139257df", + "sha256:df49e7a0861a8c36d089c1ed57d308623d60416dab2647a4a17fe050ba85de0e", + "sha256:df933278128ea1cd77772673c73954e53a1c95a4fdf41eef97c2b779271bd0bd", + "sha256:e08277a400de01bc72436a0ccd02bdf596631411f592ad985dcee21445bd0068", + "sha256:e38e63e6f3d1cec5a27e0afe90a085af8b6806ee208b33030e65b6516353f1a3", + "sha256:e55541f756f9b3ee346b840103f32779c695a19826a4c442b7954550a0972040", + "sha256:ec4e55f79b1c4ffb2eecd8a0cfba9955a2588497d96851f4c8f99aa4a1d39b12", + "sha256:ed1a53de42fbe34853ba90513cea21673481cd81ed1be739f7f2efb931b24916", + "sha256:ed541d70698978a20eb63d8c5d72f2cc6d7079d9d90f6b50bad07826f1320f5f", + "sha256:f09e2ff1f17c2b51f2bc76d1cc33da96298f0a036a137f5440ab3ec5360b624f", + "sha256:f220b0eea5965dec25480b6333c788fb72ce5f9129e8759ef876a1d805d00801", + "sha256:f3e0da4ebaef65158d4dfd7d3678aad692f7666877df0002b8a522cdf088f231", + "sha256:f455ee30a9d61d3e1a15abd5068827773d6e4dc513e795f380cdd59932c782d5", + "sha256:f5ef8f42bec47f21d07668a043f077d507e5bf4e668d5c6dfe6aaba89de1a5b8", + "sha256:f69a8e0b033b747bb3e36a44e7732f0c99f7edd5cea723d45bc0d6e95377ffee", + "sha256:ff02b6d461a6de369f07ec15e465a88895f3223eb75073ffea56b84d9331f607" ], "markers": "python_version >= '3.8'", - "version": "==2.18.4" + "version": "==2.23.4" }, "pyjwt": { "hashes": [ - "sha256:57e28d156e3d5c10088e0c68abb90bfac3df82b40a71bd0daa20c65ccd5c23de", - "sha256:59127c392cc44c2da5bb3192169a91f429924e17aff6534d70fdc02ab3e04320" + "sha256:3b02fb0f44517787776cf48f2ae25d8e14f300e6d7545a4315cee571a415e850", + "sha256:7e1e5b56cc735432a7369cbfa0efe50fa113ebecdc04ae6922deba8b84582d0c" ], - "markers": "python_version >= '3.7'", - "version": "==2.8.0" + "markers": "python_version >= '3.8'", + "version": "==2.9.0" }, "pyparsing": { "hashes": [ - "sha256:a1bac0ce561155ecc3ed78ca94d3c9378656ad4c94c1270de543f621420f94ad", - "sha256:f9db75911801ed778fe61bb643079ff86601aca99fcae6345aa67292038fb742" + "sha256:93d9577b88da0bbea8cc8334ee8b918ed014968fd2ec383e868fb8afb1ccef84", + "sha256:cbf74e27246d595d9a74b186b810f6fbb86726dbf3b9532efb343f6d7294fe9c" ], - "markers": "python_full_version >= '3.6.8'", - "version": "==3.1.2" + "markers": "python_version >= '3.9'", + "version": "==3.2.0" }, "pytest": { "hashes": [ - "sha256:c434598117762e2bd304e526244f67bf66bbd7b5d6cf22138be51ff661980343", - "sha256:de4bb8104e201939ccdc688b27a89a7be2079b22e2bd2b07f806b6ba71117977" + "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181", + "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2" ], "index": "pypi", - "version": "==8.2.2" + "markers": "python_version >= '3.8'", + "version": "==8.3.3" }, "python-dateutil": { "hashes": [ "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", "version": "==2.9.0.post0" }, "python-dotenv": { @@ -1068,71 +1273,74 @@ "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a" ], "index": "pypi", + "markers": "python_version >= '3.8'", "version": "==1.0.1" }, "pytz": { "hashes": [ - "sha256:2a29735ea9c18baf14b448846bde5a48030ed267578472d8955cd0e7443a9812", - "sha256:328171f4e3623139da4983451950b28e95ac706e13f3f2630a879749e7a8b319" + "sha256:2aa355083c50a0f93fa581709deac0c9ad65cca8a9e9beac660adcbd493c798a", + "sha256:31c7c1817eb7fae7ca4b8c7ee50c72f93aa2dd863de768e1ef4245d426aa0725" ], - "version": "==2024.1" + "version": "==2024.2" }, "pyyaml": { "hashes": [ - "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5", - "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc", - "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df", - "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741", - "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206", - "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27", - "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595", - "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62", - "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98", - "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696", - "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290", - "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9", - "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d", - "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6", - "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867", - "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47", - "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486", - "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6", - "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3", - "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007", - "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938", - "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0", - "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c", - "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735", - "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d", - "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28", - "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4", - "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba", - "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8", - "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef", - "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5", - "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd", - "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3", - "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0", - "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515", - "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c", - "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c", - "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924", - "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34", - "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43", - "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859", - "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673", - "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54", - "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a", - "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b", - "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab", - "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa", - "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c", - "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585", - "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d", - "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f" + "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff", + "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", + "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086", + "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e", + "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", + "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5", + "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", + "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee", + "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", + "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68", + "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a", + "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf", + "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99", + "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8", + "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85", + "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19", + "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", + "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a", + "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", + "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317", + "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c", + "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631", + "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d", + "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", + "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", + "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e", + "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b", + "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", + "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", + "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706", + "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", + "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237", + "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", + "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083", + "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180", + "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", + "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e", + "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f", + "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725", + "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", + "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", + "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774", + "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", + "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", + "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5", + "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d", + "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290", + "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44", + "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed", + "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", + "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", + "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12", + "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4" ], - "markers": "python_version >= '3.6'", - "version": "==6.0.1" + "markers": "python_version >= '3.8'", + "version": "==6.0.2" }, "rdflib": { "hashes": [ @@ -1140,6 +1348,7 @@ "sha256:9995eb8569428059b8c1affd26b25eac510d64f5043d9ce8c84e0d0036e995ae" ], "index": "pypi", + "markers": "python_full_version >= '3.8.1' and python_full_version < '4.0.0'", "version": "==7.0.0" }, "referencing": { @@ -1160,171 +1369,175 @@ }, "rpds-py": { "hashes": [ - "sha256:05f3d615099bd9b13ecf2fc9cf2d839ad3f20239c678f461c753e93755d629ee", - "sha256:06d218939e1bf2ca50e6b0ec700ffe755e5216a8230ab3e87c059ebb4ea06afc", - "sha256:07f2139741e5deb2c5154a7b9629bc5aa48c766b643c1a6750d16f865a82c5fc", - "sha256:08d74b184f9ab6289b87b19fe6a6d1a97fbfea84b8a3e745e87a5de3029bf944", - "sha256:0abeee75434e2ee2d142d650d1e54ac1f8b01e6e6abdde8ffd6eeac6e9c38e20", - "sha256:154bf5c93d79558b44e5b50cc354aa0459e518e83677791e6adb0b039b7aa6a7", - "sha256:17c6d2155e2423f7e79e3bb18151c686d40db42d8645e7977442170c360194d4", - "sha256:1805d5901779662d599d0e2e4159d8a82c0b05faa86ef9222bf974572286b2b6", - "sha256:19ba472b9606c36716062c023afa2484d1e4220548751bda14f725a7de17b4f6", - "sha256:19e515b78c3fc1039dd7da0a33c28c3154458f947f4dc198d3c72db2b6b5dc93", - "sha256:1d54f74f40b1f7aaa595a02ff42ef38ca654b1469bef7d52867da474243cc633", - "sha256:207c82978115baa1fd8d706d720b4a4d2b0913df1c78c85ba73fe6c5804505f0", - "sha256:2625f03b105328729f9450c8badda34d5243231eef6535f80064d57035738360", - "sha256:27bba383e8c5231cd559affe169ca0b96ec78d39909ffd817f28b166d7ddd4d8", - "sha256:2c3caec4ec5cd1d18e5dd6ae5194d24ed12785212a90b37f5f7f06b8bedd7139", - "sha256:2cc7c1a47f3a63282ab0f422d90ddac4aa3034e39fc66a559ab93041e6505da7", - "sha256:2fc24a329a717f9e2448f8cd1f960f9dac4e45b6224d60734edeb67499bab03a", - "sha256:312fe69b4fe1ffbe76520a7676b1e5ac06ddf7826d764cc10265c3b53f96dbe9", - "sha256:32b7daaa3e9389db3695964ce8e566e3413b0c43e3394c05e4b243a4cd7bef26", - "sha256:338dee44b0cef8b70fd2ef54b4e09bb1b97fc6c3a58fea5db6cc083fd9fc2724", - "sha256:352a88dc7892f1da66b6027af06a2e7e5d53fe05924cc2cfc56495b586a10b72", - "sha256:35b2b771b13eee8729a5049c976197ff58a27a3829c018a04341bcf1ae409b2b", - "sha256:38e14fb4e370885c4ecd734f093a2225ee52dc384b86fa55fe3f74638b2cfb09", - "sha256:3c20f05e8e3d4fc76875fc9cb8cf24b90a63f5a1b4c5b9273f0e8225e169b100", - "sha256:3dd3cd86e1db5aadd334e011eba4e29d37a104b403e8ca24dcd6703c68ca55b3", - "sha256:489bdfe1abd0406eba6b3bb4fdc87c7fa40f1031de073d0cfb744634cc8fa261", - "sha256:48c2faaa8adfacefcbfdb5f2e2e7bdad081e5ace8d182e5f4ade971f128e6bb3", - "sha256:4a98a1f0552b5f227a3d6422dbd61bc6f30db170939bd87ed14f3c339aa6c7c9", - "sha256:4adec039b8e2928983f885c53b7cc4cda8965b62b6596501a0308d2703f8af1b", - "sha256:4e0ee01ad8260184db21468a6e1c37afa0529acc12c3a697ee498d3c2c4dcaf3", - "sha256:51584acc5916212e1bf45edd17f3a6b05fe0cbb40482d25e619f824dccb679de", - "sha256:531796fb842b53f2695e94dc338929e9f9dbf473b64710c28af5a160b2a8927d", - "sha256:5463c47c08630007dc0fe99fb480ea4f34a89712410592380425a9b4e1611d8e", - "sha256:5c45a639e93a0c5d4b788b2613bd637468edd62f8f95ebc6fcc303d58ab3f0a8", - "sha256:6031b25fb1b06327b43d841f33842b383beba399884f8228a6bb3df3088485ff", - "sha256:607345bd5912aacc0c5a63d45a1f73fef29e697884f7e861094e443187c02be5", - "sha256:618916f5535784960f3ecf8111581f4ad31d347c3de66d02e728de460a46303c", - "sha256:636a15acc588f70fda1661234761f9ed9ad79ebed3f2125d44be0862708b666e", - "sha256:673fdbbf668dd958eff750e500495ef3f611e2ecc209464f661bc82e9838991e", - "sha256:6afd80f6c79893cfc0574956f78a0add8c76e3696f2d6a15bca2c66c415cf2d4", - "sha256:6b5ff7e1d63a8281654b5e2896d7f08799378e594f09cf3674e832ecaf396ce8", - "sha256:6c4c4c3f878df21faf5fac86eda32671c27889e13570645a9eea0a1abdd50922", - "sha256:6cd8098517c64a85e790657e7b1e509b9fe07487fd358e19431cb120f7d96338", - "sha256:6d1e42d2735d437e7e80bab4d78eb2e459af48c0a46e686ea35f690b93db792d", - "sha256:6e30ac5e329098903262dc5bdd7e2086e0256aa762cc8b744f9e7bf2a427d3f8", - "sha256:70a838f7754483bcdc830444952fd89645569e7452e3226de4a613a4c1793fb2", - "sha256:720edcb916df872d80f80a1cc5ea9058300b97721efda8651efcd938a9c70a72", - "sha256:732672fbc449bab754e0b15356c077cc31566df874964d4801ab14f71951ea80", - "sha256:740884bc62a5e2bbb31e584f5d23b32320fd75d79f916f15a788d527a5e83644", - "sha256:7700936ef9d006b7ef605dc53aa364da2de5a3aa65516a1f3ce73bf82ecfc7ae", - "sha256:7732770412bab81c5a9f6d20aeb60ae943a9b36dcd990d876a773526468e7163", - "sha256:7750569d9526199c5b97e5a9f8d96a13300950d910cf04a861d96f4273d5b104", - "sha256:7f1944ce16401aad1e3f7d312247b3d5de7981f634dc9dfe90da72b87d37887d", - "sha256:81c5196a790032e0fc2464c0b4ab95f8610f96f1f2fa3d4deacce6a79852da60", - "sha256:8352f48d511de5f973e4f2f9412736d7dea76c69faa6d36bcf885b50c758ab9a", - "sha256:8927638a4d4137a289e41d0fd631551e89fa346d6dbcfc31ad627557d03ceb6d", - "sha256:8c7672e9fba7425f79019db9945b16e308ed8bc89348c23d955c8c0540da0a07", - "sha256:8d2e182c9ee01135e11e9676e9a62dfad791a7a467738f06726872374a83db49", - "sha256:910e71711d1055b2768181efa0a17537b2622afeb0424116619817007f8a2b10", - "sha256:942695a206a58d2575033ff1e42b12b2aece98d6003c6bc739fbf33d1773b12f", - "sha256:9437ca26784120a279f3137ee080b0e717012c42921eb07861b412340f85bae2", - "sha256:967342e045564cef76dfcf1edb700b1e20838d83b1aa02ab313e6a497cf923b8", - "sha256:998125738de0158f088aef3cb264a34251908dd2e5d9966774fdab7402edfab7", - "sha256:9e6934d70dc50f9f8ea47081ceafdec09245fd9f6032669c3b45705dea096b88", - "sha256:a3d456ff2a6a4d2adcdf3c1c960a36f4fd2fec6e3b4902a42a384d17cf4e7a65", - "sha256:a7b28c5b066bca9a4eb4e2f2663012debe680f097979d880657f00e1c30875a0", - "sha256:a888e8bdb45916234b99da2d859566f1e8a1d2275a801bb8e4a9644e3c7e7909", - "sha256:aa3679e751408d75a0b4d8d26d6647b6d9326f5e35c00a7ccd82b78ef64f65f8", - "sha256:aaa71ee43a703c321906813bb252f69524f02aa05bf4eec85f0c41d5d62d0f4c", - "sha256:b646bf655b135ccf4522ed43d6902af37d3f5dbcf0da66c769a2b3938b9d8184", - "sha256:b906b5f58892813e5ba5c6056d6a5ad08f358ba49f046d910ad992196ea61397", - "sha256:b9bb1f182a97880f6078283b3505a707057c42bf55d8fca604f70dedfdc0772a", - "sha256:bd1105b50ede37461c1d51b9698c4f4be6e13e69a908ab7751e3807985fc0346", - "sha256:bf18932d0003c8c4d51a39f244231986ab23ee057d235a12b2684ea26a353590", - "sha256:c273e795e7a0f1fddd46e1e3cb8be15634c29ae8ff31c196debb620e1edb9333", - "sha256:c69882964516dc143083d3795cb508e806b09fc3800fd0d4cddc1df6c36e76bb", - "sha256:c827576e2fa017a081346dce87d532a5310241648eb3700af9a571a6e9fc7e74", - "sha256:cbfbea39ba64f5e53ae2915de36f130588bba71245b418060ec3330ebf85678e", - "sha256:ce0bb20e3a11bd04461324a6a798af34d503f8d6f1aa3d2aa8901ceaf039176d", - "sha256:d0cee71bc618cd93716f3c1bf56653740d2d13ddbd47673efa8bf41435a60daa", - "sha256:d21be4770ff4e08698e1e8e0bce06edb6ea0626e7c8f560bc08222880aca6a6f", - "sha256:d31dea506d718693b6b2cffc0648a8929bdc51c70a311b2770f09611caa10d53", - "sha256:d44607f98caa2961bab4fa3c4309724b185b464cdc3ba6f3d7340bac3ec97cc1", - "sha256:d58ad6317d188c43750cb76e9deacf6051d0f884d87dc6518e0280438648a9ac", - "sha256:d70129cef4a8d979caa37e7fe957202e7eee8ea02c5e16455bc9808a59c6b2f0", - "sha256:d85164315bd68c0806768dc6bb0429c6f95c354f87485ee3593c4f6b14def2bd", - "sha256:d960de62227635d2e61068f42a6cb6aae91a7fe00fca0e3aeed17667c8a34611", - "sha256:dc48b479d540770c811fbd1eb9ba2bb66951863e448efec2e2c102625328e92f", - "sha256:e1735502458621921cee039c47318cb90b51d532c2766593be6207eec53e5c4c", - "sha256:e2be6e9dd4111d5b31ba3b74d17da54a8319d8168890fbaea4b9e5c3de630ae5", - "sha256:e4c39ad2f512b4041343ea3c7894339e4ca7839ac38ca83d68a832fc8b3748ab", - "sha256:ed402d6153c5d519a0faf1bb69898e97fb31613b49da27a84a13935ea9164dfc", - "sha256:ee17cd26b97d537af8f33635ef38be873073d516fd425e80559f4585a7b90c43", - "sha256:f3027be483868c99b4985fda802a57a67fdf30c5d9a50338d9db646d590198da", - "sha256:f5bab211605d91db0e2995a17b5c6ee5edec1270e46223e513eaa20da20076ac", - "sha256:f6f8e3fecca256fefc91bb6765a693d96692459d7d4c644660a9fff32e517843", - "sha256:f7afbfee1157e0f9376c00bb232e80a60e59ed716e3211a80cb8506550671e6e", - "sha256:fa242ac1ff583e4ec7771141606aafc92b361cd90a05c30d93e343a0c2d82a89", - "sha256:fab6ce90574645a0d6c58890e9bcaac8d94dff54fb51c69e5522a7358b80ab64" + "sha256:06db23d43f26478303e954c34c75182356ca9aa7797d22c5345b16871ab9c45c", + "sha256:0e13e6952ef264c40587d510ad676a988df19adea20444c2b295e536457bc585", + "sha256:11ef6ce74616342888b69878d45e9f779b95d4bd48b382a229fe624a409b72c5", + "sha256:1259c7b3705ac0a0bd38197565a5d603218591d3f6cee6e614e380b6ba61c6f6", + "sha256:18d7585c463087bddcfa74c2ba267339f14f2515158ac4db30b1f9cbdb62c8ef", + "sha256:1e0f80b739e5a8f54837be5d5c924483996b603d5502bfff79bf33da06164ee2", + "sha256:1e5f3cd7397c8f86c8cc72d5a791071431c108edd79872cdd96e00abd8497d29", + "sha256:220002c1b846db9afd83371d08d239fdc865e8f8c5795bbaec20916a76db3318", + "sha256:22e6c9976e38f4d8c4a63bd8a8edac5307dffd3ee7e6026d97f3cc3a2dc02a0b", + "sha256:238a2d5b1cad28cdc6ed15faf93a998336eb041c4e440dd7f902528b8891b399", + "sha256:2580b0c34583b85efec8c5c5ec9edf2dfe817330cc882ee972ae650e7b5ef739", + "sha256:28527c685f237c05445efec62426d285e47a58fb05ba0090a4340b73ecda6dee", + "sha256:2cf126d33a91ee6eedc7f3197b53e87a2acdac63602c0f03a02dd69e4b138174", + "sha256:338ca4539aad4ce70a656e5187a3a31c5204f261aef9f6ab50e50bcdffaf050a", + "sha256:39ed0d010457a78f54090fafb5d108501b5aa5604cc22408fc1c0c77eac14344", + "sha256:3ad0fda1635f8439cde85c700f964b23ed5fc2d28016b32b9ee5fe30da5c84e2", + "sha256:3d2b1ad682a3dfda2a4e8ad8572f3100f95fad98cb99faf37ff0ddfe9cbf9d03", + "sha256:3d61339e9f84a3f0767b1995adfb171a0d00a1185192718a17af6e124728e0f5", + "sha256:3fde368e9140312b6e8b6c09fb9f8c8c2f00999d1823403ae90cc00480221b22", + "sha256:40ce74fc86ee4645d0a225498d091d8bc61f39b709ebef8204cb8b5a464d3c0e", + "sha256:49a8063ea4296b3a7e81a5dfb8f7b2d73f0b1c20c2af401fb0cdf22e14711a96", + "sha256:4a1f1d51eccb7e6c32ae89243cb352389228ea62f89cd80823ea7dd1b98e0b91", + "sha256:4b16aa0107ecb512b568244ef461f27697164d9a68d8b35090e9b0c1c8b27752", + "sha256:4f1ed4749a08379555cebf4650453f14452eaa9c43d0a95c49db50c18b7da075", + "sha256:4fe84294c7019456e56d93e8ababdad5a329cd25975be749c3f5f558abb48253", + "sha256:50eccbf054e62a7b2209b28dc7a22d6254860209d6753e6b78cfaeb0075d7bee", + "sha256:514b3293b64187172bc77c8fb0cdae26981618021053b30d8371c3a902d4d5ad", + "sha256:54b43a2b07db18314669092bb2de584524d1ef414588780261e31e85846c26a5", + "sha256:55fea87029cded5df854ca7e192ec7bdb7ecd1d9a3f63d5c4eb09148acf4a7ce", + "sha256:569b3ea770c2717b730b61998b6c54996adee3cef69fc28d444f3e7920313cf7", + "sha256:56e27147a5a4c2c21633ff8475d185734c0e4befd1c989b5b95a5d0db699b21b", + "sha256:57eb94a8c16ab08fef6404301c38318e2c5a32216bf5de453e2714c964c125c8", + "sha256:5a35df9f5548fd79cb2f52d27182108c3e6641a4feb0f39067911bf2adaa3e57", + "sha256:5a8c94dad2e45324fc74dce25e1645d4d14df9a4e54a30fa0ae8bad9a63928e3", + "sha256:5b4f105deeffa28bbcdff6c49b34e74903139afa690e35d2d9e3c2c2fba18cec", + "sha256:5c1dc0f53856b9cc9a0ccca0a7cc61d3d20a7088201c0937f3f4048c1718a209", + "sha256:614fdafe9f5f19c63ea02817fa4861c606a59a604a77c8cdef5aa01d28b97921", + "sha256:617c7357272c67696fd052811e352ac54ed1d9b49ab370261a80d3b6ce385045", + "sha256:65794e4048ee837494aea3c21a28ad5fc080994dfba5b036cf84de37f7ad5074", + "sha256:6632f2d04f15d1bd6fe0eedd3b86d9061b836ddca4c03d5cf5c7e9e6b7c14580", + "sha256:6c8ef2ebf76df43f5750b46851ed1cdf8f109d7787ca40035fe19fbdc1acc5a7", + "sha256:758406267907b3781beee0f0edfe4a179fbd97c0be2e9b1154d7f0a1279cf8e5", + "sha256:7e60cb630f674a31f0368ed32b2a6b4331b8350d67de53c0359992444b116dd3", + "sha256:89c19a494bf3ad08c1da49445cc5d13d8fefc265f48ee7e7556839acdacf69d0", + "sha256:8a86a9b96070674fc88b6f9f71a97d2c1d3e5165574615d1f9168ecba4cecb24", + "sha256:8bc7690f7caee50b04a79bf017a8d020c1f48c2a1077ffe172abec59870f1139", + "sha256:8d7919548df3f25374a1f5d01fbcd38dacab338ef5f33e044744b5c36729c8db", + "sha256:9426133526f69fcaba6e42146b4e12d6bc6c839b8b555097020e2b78ce908dcc", + "sha256:9824fb430c9cf9af743cf7aaf6707bf14323fb51ee74425c380f4c846ea70789", + "sha256:9bb4a0d90fdb03437c109a17eade42dfbf6190408f29b2744114d11586611d6f", + "sha256:9bc2d153989e3216b0559251b0c260cfd168ec78b1fac33dd485750a228db5a2", + "sha256:9d35cef91e59ebbeaa45214861874bc6f19eb35de96db73e467a8358d701a96c", + "sha256:a1862d2d7ce1674cffa6d186d53ca95c6e17ed2b06b3f4c476173565c862d232", + "sha256:a84ab91cbe7aab97f7446652d0ed37d35b68a465aeef8fc41932a9d7eee2c1a6", + "sha256:aa7f429242aae2947246587d2964fad750b79e8c233a2367f71b554e9447949c", + "sha256:aa9a0521aeca7d4941499a73ad7d4f8ffa3d1affc50b9ea11d992cd7eff18a29", + "sha256:ac2f4f7a98934c2ed6505aead07b979e6f999389f16b714448fb39bbaa86a489", + "sha256:ae94bd0b2f02c28e199e9bc51485d0c5601f58780636185660f86bf80c89af94", + "sha256:af0fc424a5842a11e28956e69395fbbeab2c97c42253169d87e90aac2886d751", + "sha256:b2a5db5397d82fa847e4c624b0c98fe59d2d9b7cf0ce6de09e4d2e80f8f5b3f2", + "sha256:b4c29cbbba378759ac5786730d1c3cb4ec6f8ababf5c42a9ce303dc4b3d08cda", + "sha256:b74b25f024b421d5859d156750ea9a65651793d51b76a2e9238c05c9d5f203a9", + "sha256:b7f19250ceef892adf27f0399b9e5afad019288e9be756d6919cb58892129f51", + "sha256:b80d4a7900cf6b66bb9cee5c352b2d708e29e5a37fe9bf784fa97fc11504bf6c", + "sha256:b8c00a3b1e70c1d3891f0db1b05292747f0dbcfb49c43f9244d04c70fbc40eb8", + "sha256:bb273176be34a746bdac0b0d7e4e2c467323d13640b736c4c477881a3220a989", + "sha256:c3c20f0ddeb6e29126d45f89206b8291352b8c5b44384e78a6499d68b52ae511", + "sha256:c3e130fd0ec56cb76eb49ef52faead8ff09d13f4527e9b0c400307ff72b408e1", + "sha256:c52d3f2f82b763a24ef52f5d24358553e8403ce05f893b5347098014f2d9eff2", + "sha256:c6377e647bbfd0a0b159fe557f2c6c602c159fc752fa316572f012fc0bf67150", + "sha256:c638144ce971df84650d3ed0096e2ae7af8e62ecbbb7b201c8935c370df00a2c", + "sha256:ce9845054c13696f7af7f2b353e6b4f676dab1b4b215d7fe5e05c6f8bb06f965", + "sha256:cf258ede5bc22a45c8e726b29835b9303c285ab46fc7c3a4cc770736b5304c9f", + "sha256:d0a26ffe9d4dd35e4dfdd1e71f46401cff0181c75ac174711ccff0459135fa58", + "sha256:d0b67d87bb45ed1cd020e8fbf2307d449b68abc45402fe1a4ac9e46c3c8b192b", + "sha256:d20277fd62e1b992a50c43f13fbe13277a31f8c9f70d59759c88f644d66c619f", + "sha256:d454b8749b4bd70dd0a79f428731ee263fa6995f83ccb8bada706e8d1d3ff89d", + "sha256:d4c7d1a051eeb39f5c9547e82ea27cbcc28338482242e3e0b7768033cb083821", + "sha256:d72278a30111e5b5525c1dd96120d9e958464316f55adb030433ea905866f4de", + "sha256:d72a210824facfdaf8768cf2d7ca25a042c30320b3020de2fa04640920d4e121", + "sha256:d807dc2051abe041b6649681dce568f8e10668e3c1c6543ebae58f2d7e617855", + "sha256:dbe982f38565bb50cb7fb061ebf762c2f254ca3d8c20d4006878766e84266272", + "sha256:dcedf0b42bcb4cfff4101d7771a10532415a6106062f005ab97d1d0ab5681c60", + "sha256:deb62214c42a261cb3eb04d474f7155279c1a8a8c30ac89b7dcb1721d92c3c02", + "sha256:def7400461c3a3f26e49078302e1c1b38f6752342c77e3cf72ce91ca69fb1bc1", + "sha256:df3de6b7726b52966edf29663e57306b23ef775faf0ac01a3e9f4012a24a4140", + "sha256:e1940dae14e715e2e02dfd5b0f64a52e8374a517a1e531ad9412319dc3ac7879", + "sha256:e4df1e3b3bec320790f699890d41c59d250f6beda159ea3c44c3f5bac1976940", + "sha256:e6900ecdd50ce0facf703f7a00df12374b74bbc8ad9fe0f6559947fb20f82364", + "sha256:ea438162a9fcbee3ecf36c23e6c68237479f89f962f82dae83dc15feeceb37e4", + "sha256:eb851b7df9dda52dc1415ebee12362047ce771fc36914586b2e9fcbd7d293b3e", + "sha256:ec31a99ca63bf3cd7f1a5ac9fe95c5e2d060d3c768a09bc1d16e235840861420", + "sha256:f0475242f447cc6cb8a9dd486d68b2ef7fbee84427124c232bff5f63b1fe11e5", + "sha256:f2fbf7db2012d4876fb0d66b5b9ba6591197b0f165db8d99371d976546472a24", + "sha256:f60012a73aa396be721558caa3a6fd49b3dd0033d1675c6d59c4502e870fcf0c", + "sha256:f8e604fe73ba048c06085beaf51147eaec7df856824bfe7b98657cf436623daf", + "sha256:f90a4cd061914a60bd51c68bcb4357086991bd0bb93d8aa66a6da7701370708f", + "sha256:f918a1a130a6dfe1d7fe0f105064141342e7dd1611f2e6a21cd2f5c8cb1cfb3e", + "sha256:fa518bcd7600c584bf42e6617ee8132869e877db2f76bcdc281ec6a4113a53ab", + "sha256:faefcc78f53a88f3076b7f8be0a8f8d35133a3ecf7f3770895c25f8813460f08", + "sha256:fcaeb7b57f1a1e071ebd748984359fef83ecb026325b9d4ca847c95bc7311c92", + "sha256:fd2d84f40633bc475ef2d5490b9c19543fbf18596dcb1b291e3a12ea5d722f7a", + "sha256:fdfc3a892927458d98f3d55428ae46b921d1f7543b89382fdb483f5640daaec8" ], "markers": "python_version >= '3.8'", - "version": "==0.18.1" + "version": "==0.20.0" }, "six": { "hashes": [ "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", "version": "==1.16.0" }, "sqlalchemy": { "hashes": [ - "sha256:0b0f658414ee4e4b8cbcd4a9bb0fd743c5eeb81fc858ca517217a8013d282c96", - "sha256:2196208432deebdfe3b22185d46b08f00ac9d7b01284e168c212919891289396", - "sha256:23b9fbb2f5dd9e630db70fbe47d963c7779e9c81830869bd7d137c2dc1ad05fb", - "sha256:26a6a9837589c42b16693cf7bf836f5d42218f44d198f9343dd71d3164ceeeac", - "sha256:2a21c97efcbb9f255d5c12a96ae14da873233597dfd00a3a0c4ce5b3e5e79704", - "sha256:2e2c38c2a4c5c634fe6c3c58a789712719fa1bf9b9d6ff5ebfce9a9e5b89c1ca", - "sha256:2fc47dc6185a83c8100b37acda27658fe4dbd33b7d5e7324111f6521008ab4fe", - "sha256:2fd17e3bb8058359fa61248c52c7b09a97cf3c820e54207a50af529876451808", - "sha256:352b2770097f41bff6029b280c0e03b217c2dcaddc40726f8f53ed58d8a85da4", - "sha256:3b74570d99126992d4b0f91fb87c586a574a5872651185de8297c6f90055ae42", - "sha256:3cb8a66b167b033ec72c3812ffc8441d4e9f5f78f5e31e54dcd4c90a4ca5bebc", - "sha256:3f9faef422cfbb8fd53716cd14ba95e2ef655400235c3dfad1b5f467ba179c8c", - "sha256:4b600e9a212ed59355813becbcf282cfda5c93678e15c25a0ef896b354423238", - "sha256:501ff052229cb79dd4c49c402f6cb03b5a40ae4771efc8bb2bfac9f6c3d3508f", - "sha256:56d51ae825d20d604583f82c9527d285e9e6d14f9a5516463d9705dab20c3740", - "sha256:597fec37c382a5442ffd471f66ce12d07d91b281fd474289356b1a0041bdf31d", - "sha256:5a48ac4d359f058474fadc2115f78a5cdac9988d4f99eae44917f36aa1476327", - "sha256:5b6cf796d9fcc9b37011d3f9936189b3c8074a02a4ed0c0fbbc126772c31a6d4", - "sha256:66f63278db425838b3c2b1c596654b31939427016ba030e951b292e32b99553e", - "sha256:69f3e3c08867a8e4856e92d7afb618b95cdee18e0bc1647b77599722c9a28911", - "sha256:6e2622844551945db81c26a02f27d94145b561f9d4b0c39ce7bfd2fda5776dac", - "sha256:6f77c4f042ad493cb8595e2f503c7a4fe44cd7bd59c7582fd6d78d7e7b8ec52c", - "sha256:74afabeeff415e35525bf7a4ecdab015f00e06456166a2eba7590e49f8db940e", - "sha256:750900a471d39a7eeba57580b11983030517a1f512c2cb287d5ad0fcf3aebd58", - "sha256:78fe11dbe37d92667c2c6e74379f75746dc947ee505555a0197cfba9a6d4f1a4", - "sha256:79a40771363c5e9f3a77f0e28b3302801db08040928146e6808b5b7a40749c88", - "sha256:7bd112be780928c7f493c1a192cd8c5fc2a2a7b52b790bc5a84203fb4381c6be", - "sha256:8a41514c1a779e2aa9a19f67aaadeb5cbddf0b2b508843fcd7bafdf4c6864005", - "sha256:9f2bee229715b6366f86a95d497c347c22ddffa2c7c96143b59a2aa5cc9eebbc", - "sha256:9fea3d0884e82d1e33226935dac990b967bef21315cbcc894605db3441347443", - "sha256:afb6dde6c11ea4525318e279cd93c8734b795ac8bb5dda0eedd9ebaca7fa23f1", - "sha256:b607489dd4a54de56984a0c7656247504bd5523d9d0ba799aef59d4add009484", - "sha256:b6e22630e89f0e8c12332b2b4c282cb01cf4da0d26795b7eae16702a608e7ca1", - "sha256:b9c01990d9015df2c6f818aa8f4297d42ee71c9502026bb074e713d496e26b67", - "sha256:bd15026f77420eb2b324dcb93551ad9c5f22fab2c150c286ef1dc1160f110203", - "sha256:c06fb43a51ccdff3b4006aafee9fcf15f63f23c580675f7734245ceb6b6a9e05", - "sha256:c76c81c52e1e08f12f4b6a07af2b96b9b15ea67ccdd40ae17019f1c373faa227", - "sha256:ccaf1b0c90435b6e430f5dd30a5aede4764942a695552eb3a4ab74ed63c5b8d3", - "sha256:cd1591329333daf94467e699e11015d9c944f44c94d2091f4ac493ced0119449", - "sha256:cd5b94d4819c0c89280b7c6109c7b788a576084bf0a480ae17c227b0bc41e109", - "sha256:d337bf94052856d1b330d5fcad44582a30c532a2463776e1651bd3294ee7e58b", - "sha256:dc251477eae03c20fae8db9c1c23ea2ebc47331bcd73927cdcaecd02af98d3c3", - "sha256:dc6d69f8829712a4fd799d2ac8d79bdeff651c2301b081fd5d3fe697bd5b4ab9", - "sha256:f2a213c1b699d3f5768a7272de720387ae0122f1becf0901ed6eaa1abd1baf6c", - "sha256:f3ad7f221d8a69d32d197e5968d798217a4feebe30144986af71ada8c548e9fa", - "sha256:f43e93057cf52a227eda401251c72b6fbe4756f35fa6bfebb5d73b86881e59b0", - "sha256:f68470edd70c3ac3b6cd5c2a22a8daf18415203ca1b036aaeb9b0fb6f54e8298", - "sha256:fa4b1af3e619b5b0b435e333f3967612db06351217c58bfb50cee5f003db2a5a", - "sha256:fc6b14e8602f59c6ba893980bea96571dd0ed83d8ebb9c4479d9ed5425d562e9" + "sha256:016b2e665f778f13d3c438651dd4de244214b527a275e0acf1d44c05bc6026a9", + "sha256:032d979ce77a6c2432653322ba4cbeabf5a6837f704d16fa38b5a05d8e21fa00", + "sha256:0375a141e1c0878103eb3d719eb6d5aa444b490c96f3fedab8471c7f6ffe70ee", + "sha256:042622a5306c23b972192283f4e22372da3b8ddf5f7aac1cc5d9c9b222ab3ff6", + "sha256:05c3f58cf91683102f2f0265c0db3bd3892e9eedabe059720492dbaa4f922da1", + "sha256:0630774b0977804fba4b6bbea6852ab56c14965a2b0c7fc7282c5f7d90a1ae72", + "sha256:0f9f3f9a3763b9c4deb8c5d09c4cc52ffe49f9876af41cc1b2ad0138878453cf", + "sha256:1b56961e2d31389aaadf4906d453859f35302b4eb818d34a26fab72596076bb8", + "sha256:22b83aed390e3099584b839b93f80a0f4a95ee7f48270c97c90acd40ee646f0b", + "sha256:25b0f63e7fcc2a6290cb5f7f5b4fc4047843504983a28856ce9b35d8f7de03cc", + "sha256:2a275a806f73e849e1c309ac11108ea1a14cd7058577aba962cd7190e27c9e3c", + "sha256:2ab3f0336c0387662ce6221ad30ab3a5e6499aab01b9790879b6578fd9b8faa1", + "sha256:2e795c2f7d7249b75bb5f479b432a51b59041580d20599d4e112b5f2046437a3", + "sha256:3655af10ebcc0f1e4e06c5900bb33e080d6a1fa4228f502121f28a3b1753cde5", + "sha256:4668bd8faf7e5b71c0319407b608f278f279668f358857dbfd10ef1954ac9f90", + "sha256:4c31943b61ed8fdd63dfd12ccc919f2bf95eefca133767db6fbbd15da62078ec", + "sha256:4fdcd72a789c1c31ed242fd8c1bcd9ea186a98ee8e5408a50e610edfef980d71", + "sha256:627dee0c280eea91aed87b20a1f849e9ae2fe719d52cbf847c0e0ea34464b3f7", + "sha256:67219632be22f14750f0d1c70e62f204ba69d28f62fd6432ba05ab295853de9b", + "sha256:6921ee01caf375363be5e9ae70d08ce7ca9d7e0e8983183080211a062d299468", + "sha256:69683e02e8a9de37f17985905a5eca18ad651bf592314b4d3d799029797d0eb3", + "sha256:6a93c5a0dfe8d34951e8a6f499a9479ffb9258123551fa007fc708ae2ac2bc5e", + "sha256:732e026240cdd1c1b2e3ac515c7a23820430ed94292ce33806a95869c46bd139", + "sha256:7befc148de64b6060937231cbff8d01ccf0bfd75aa26383ffdf8d82b12ec04ff", + "sha256:890da8cd1941fa3dab28c5bac3b9da8502e7e366f895b3b8e500896f12f94d11", + "sha256:89b64cd8898a3a6f642db4eb7b26d1b28a497d4022eccd7717ca066823e9fb01", + "sha256:8a6219108a15fc6d24de499d0d515c7235c617b2540d97116b663dade1a54d62", + "sha256:8cdf1a0dbe5ced887a9b127da4ffd7354e9c1a3b9bb330dce84df6b70ccb3a8d", + "sha256:8d625eddf7efeba2abfd9c014a22c0f6b3796e0ffb48f5d5ab106568ef01ff5a", + "sha256:93a71c8601e823236ac0e5d087e4f397874a421017b3318fd92c0b14acf2b6db", + "sha256:9509c4123491d0e63fb5e16199e09f8e262066e58903e84615c301dde8fa2e87", + "sha256:a29762cd3d116585278ffb2e5b8cc311fb095ea278b96feef28d0b423154858e", + "sha256:a62dd5d7cc8626a3634208df458c5fe4f21200d96a74d122c83bc2015b333bc1", + "sha256:ada603db10bb865bbe591939de854faf2c60f43c9b763e90f653224138f910d9", + "sha256:aee110e4ef3c528f3abbc3c2018c121e708938adeeff9006428dd7c8555e9b3f", + "sha256:b76d63495b0508ab9fc23f8152bac63205d2a704cd009a2b0722f4c8e0cba8e0", + "sha256:c0d8326269dbf944b9201911b0d9f3dc524d64779a07518199a58384c3d37a44", + "sha256:c41411e192f8d3ea39ea70e0fae48762cd11a2244e03751a98bd3c0ca9a4e936", + "sha256:c68fe3fcde03920c46697585620135b4ecfdfc1ed23e75cc2c2ae9f8502c10b8", + "sha256:cb8bea573863762bbf45d1e13f87c2d2fd32cee2dbd50d050f83f87429c9e1ea", + "sha256:cc32b2990fc34380ec2f6195f33a76b6cdaa9eecf09f0c9404b74fc120aef36f", + "sha256:ccae5de2a0140d8be6838c331604f91d6fafd0735dbdcee1ac78fc8fbaba76b4", + "sha256:d299797d75cd747e7797b1b41817111406b8b10a4f88b6e8fe5b5e59598b43b0", + "sha256:e04b622bb8a88f10e439084486f2f6349bf4d50605ac3e445869c7ea5cf0fa8c", + "sha256:e11d7ea4d24f0a262bccf9a7cd6284c976c5369dac21db237cff59586045ab9f", + "sha256:e21f66748ab725ade40fa7af8ec8b5019c68ab00b929f6643e1b1af461eddb60", + "sha256:eb60b026d8ad0c97917cb81d3662d0b39b8ff1335e3fabb24984c6acd0c900a2", + "sha256:f021d334f2ca692523aaf7bbf7592ceff70c8594fad853416a81d66b35e3abf9", + "sha256:f552023710d4b93d8fb29a91fadf97de89c5926c6bd758897875435f2a939f33" ], "markers": "python_version >= '3.7'", - "version": "==2.0.31" + "version": "==2.0.35" }, "sqlalchemy-utils": { "hashes": [ @@ -1332,6 +1545,7 @@ "sha256:bc599c8c3b3319e53ce6c5c3c471120bd325d0071fb6f38a10e924e3d07b9990" ], "index": "pypi", + "markers": "python_version >= '3.7'", "version": "==0.41.2" }, "testcontainers-core": { @@ -1346,15 +1560,16 @@ "sha256:0bdf270b5b7f53915832f7c31dd2bd3ffdc20b534ea6b32231cc7003049bd0e1" ], "index": "pypi", + "markers": "python_version >= '3.7'", "version": "==0.0.1rc1" }, "tinydb": { "hashes": [ - "sha256:30c06d12383d7c332e404ca6a6103fb2b32cbf25712689648c39d9a6bd34bd3d", - "sha256:6dd686a9c5a75dfa9280088fd79a419aefe19cd7f4bd85eba203540ef856d564" + "sha256:f7dfc39b8d7fda7a1ca62a8dbb449ffd340a117c1206b68c50b1a481fb95181d", + "sha256:f97030ee5cbc91eeadd1d7af07ab0e48ceb04aa63d4a983adbaca4cba16e86c3" ], - "markers": "python_version >= '3.7' and python_version < '4.0'", - "version": "==4.8.0" + "markers": "python_version >= '3.8' and python_version < '4.0'", + "version": "==4.8.2" }, "tuspy": { "hashes": [ @@ -1374,27 +1589,27 @@ }, "tzdata": { "hashes": [ - "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd", - "sha256:9068bc196136463f5245e51efda838afa15aaeca9903f49050dfa2679db4d252" + "sha256:7d85cc416e9382e69095b7bdf4afd9e3880418a2413feec7069d533d6b4e31cc", + "sha256:a48093786cdcde33cad18c2555e8532f34422074448fbc874186f0abd79565cd" ], "markers": "python_version >= '2'", - "version": "==2024.1" + "version": "==2024.2" }, "urllib3": { "hashes": [ - "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472", - "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168" + "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac", + "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9" ], "markers": "python_version >= '3.10'", - "version": "==2.2.2" + "version": "==2.2.3" }, "werkzeug": { "hashes": [ - "sha256:097e5bfda9f0aba8da6b8545146def481d06aa7d3266e7448e2cccf67dd8bd18", - "sha256:fc9645dc43e03e4d630d23143a04a7f947a9a3b5727cd535fdfe155a17cc48c8" + "sha256:02c9eb92b7d6c06f31a782811505d2157837cea66aaede3e217c7c27c039476c", + "sha256:34f2371506b250df4d4f84bfe7b0921e4762525762bbd936614909fe25cd7306" ], "markers": "python_version >= '3.8'", - "version": "==3.0.3" + "version": "==3.0.4" }, "wrapt": { "hashes": [ @@ -1474,159 +1689,305 @@ }, "yarl": { "hashes": [ - "sha256:008d3e808d03ef28542372d01057fd09168419cdc8f848efe2804f894ae03e51", - "sha256:03caa9507d3d3c83bca08650678e25364e1843b484f19986a527630ca376ecce", - "sha256:07574b007ee20e5c375a8fe4a0789fad26db905f9813be0f9fef5a68080de559", - "sha256:09efe4615ada057ba2d30df871d2f668af661e971dfeedf0c159927d48bbeff0", - "sha256:0d2454f0aef65ea81037759be5ca9947539667eecebca092733b2eb43c965a81", - "sha256:0e9d124c191d5b881060a9e5060627694c3bdd1fe24c5eecc8d5d7d0eb6faabc", - "sha256:18580f672e44ce1238b82f7fb87d727c4a131f3a9d33a5e0e82b793362bf18b4", - "sha256:1f23e4fe1e8794f74b6027d7cf19dc25f8b63af1483d91d595d4a07eca1fb26c", - "sha256:206a55215e6d05dbc6c98ce598a59e6fbd0c493e2de4ea6cc2f4934d5a18d130", - "sha256:23d32a2594cb5d565d358a92e151315d1b2268bc10f4610d098f96b147370136", - "sha256:26a1dc6285e03f3cc9e839a2da83bcbf31dcb0d004c72d0730e755b33466c30e", - "sha256:29e0f83f37610f173eb7e7b5562dd71467993495e568e708d99e9d1944f561ec", - "sha256:2b134fd795e2322b7684155b7855cc99409d10b2e408056db2b93b51a52accc7", - "sha256:2d47552b6e52c3319fede1b60b3de120fe83bde9b7bddad11a69fb0af7db32f1", - "sha256:357495293086c5b6d34ca9616a43d329317feab7917518bc97a08f9e55648455", - "sha256:35a2b9396879ce32754bd457d31a51ff0a9d426fd9e0e3c33394bf4b9036b099", - "sha256:3777ce5536d17989c91696db1d459574e9a9bd37660ea7ee4d3344579bb6f129", - "sha256:3986b6f41ad22988e53d5778f91855dc0399b043fc8946d4f2e68af22ee9ff10", - "sha256:44d8ffbb9c06e5a7f529f38f53eda23e50d1ed33c6c869e01481d3fafa6b8142", - "sha256:49a180c2e0743d5d6e0b4d1a9e5f633c62eca3f8a86ba5dd3c471060e352ca98", - "sha256:4aa9741085f635934f3a2583e16fcf62ba835719a8b2b28fb2917bb0537c1dfa", - "sha256:4b21516d181cd77ebd06ce160ef8cc2a5e9ad35fb1c5930882baff5ac865eee7", - "sha256:4b3c1ffe10069f655ea2d731808e76e0f452fc6c749bea04781daf18e6039525", - "sha256:4c7d56b293cc071e82532f70adcbd8b61909eec973ae9d2d1f9b233f3d943f2c", - "sha256:4e9035df8d0880b2f1c7f5031f33f69e071dfe72ee9310cfc76f7b605958ceb9", - "sha256:54525ae423d7b7a8ee81ba189f131054defdb122cde31ff17477951464c1691c", - "sha256:549d19c84c55d11687ddbd47eeb348a89df9cb30e1993f1b128f4685cd0ebbf8", - "sha256:54beabb809ffcacbd9d28ac57b0db46e42a6e341a030293fb3185c409e626b8b", - "sha256:566db86717cf8080b99b58b083b773a908ae40f06681e87e589a976faf8246bf", - "sha256:5a2e2433eb9344a163aced6a5f6c9222c0786e5a9e9cac2c89f0b28433f56e23", - "sha256:5aef935237d60a51a62b86249839b51345f47564208c6ee615ed2a40878dccdd", - "sha256:604f31d97fa493083ea21bd9b92c419012531c4e17ea6da0f65cacdcf5d0bd27", - "sha256:63b20738b5aac74e239622d2fe30df4fca4942a86e31bf47a81a0e94c14df94f", - "sha256:686a0c2f85f83463272ddffd4deb5e591c98aac1897d65e92319f729c320eece", - "sha256:6a962e04b8f91f8c4e5917e518d17958e3bdee71fd1d8b88cdce74dd0ebbf434", - "sha256:6ad6d10ed9b67a382b45f29ea028f92d25bc0bc1daf6c5b801b90b5aa70fb9ec", - "sha256:6f5cb257bc2ec58f437da2b37a8cd48f666db96d47b8a3115c29f316313654ff", - "sha256:6fe79f998a4052d79e1c30eeb7d6c1c1056ad33300f682465e1b4e9b5a188b78", - "sha256:7855426dfbddac81896b6e533ebefc0af2f132d4a47340cee6d22cac7190022d", - "sha256:7d5aaac37d19b2904bb9dfe12cdb08c8443e7ba7d2852894ad448d4b8f442863", - "sha256:801e9264d19643548651b9db361ce3287176671fb0117f96b5ac0ee1c3530d53", - "sha256:81eb57278deb6098a5b62e88ad8281b2ba09f2f1147c4767522353eaa6260b31", - "sha256:824d6c50492add5da9374875ce72db7a0733b29c2394890aef23d533106e2b15", - "sha256:8397a3817d7dcdd14bb266283cd1d6fc7264a48c186b986f32e86d86d35fbac5", - "sha256:848cd2a1df56ddbffeb375535fb62c9d1645dde33ca4d51341378b3f5954429b", - "sha256:84fc30f71689d7fc9168b92788abc977dc8cefa806909565fc2951d02f6b7d57", - "sha256:8619d6915b3b0b34420cf9b2bb6d81ef59d984cb0fde7544e9ece32b4b3043c3", - "sha256:8a854227cf581330ffa2c4824d96e52ee621dd571078a252c25e3a3b3d94a1b1", - "sha256:8be9e837ea9113676e5754b43b940b50cce76d9ed7d2461df1af39a8ee674d9f", - "sha256:928cecb0ef9d5a7946eb6ff58417ad2fe9375762382f1bf5c55e61645f2c43ad", - "sha256:957b4774373cf6f709359e5c8c4a0af9f6d7875db657adb0feaf8d6cb3c3964c", - "sha256:992f18e0ea248ee03b5a6e8b3b4738850ae7dbb172cc41c966462801cbf62cf7", - "sha256:9fc5fc1eeb029757349ad26bbc5880557389a03fa6ada41703db5e068881e5f2", - "sha256:a00862fb23195b6b8322f7d781b0dc1d82cb3bcac346d1e38689370cc1cc398b", - "sha256:a3a6ed1d525bfb91b3fc9b690c5a21bb52de28c018530ad85093cc488bee2dd2", - "sha256:a6327976c7c2f4ee6816eff196e25385ccc02cb81427952414a64811037bbc8b", - "sha256:a7409f968456111140c1c95301cadf071bd30a81cbd7ab829169fb9e3d72eae9", - "sha256:a825ec844298c791fd28ed14ed1bffc56a98d15b8c58a20e0e08c1f5f2bea1be", - "sha256:a8c1df72eb746f4136fe9a2e72b0c9dc1da1cbd23b5372f94b5820ff8ae30e0e", - "sha256:a9bd00dc3bc395a662900f33f74feb3e757429e545d831eef5bb280252631984", - "sha256:aa102d6d280a5455ad6a0f9e6d769989638718e938a6a0a2ff3f4a7ff8c62cc4", - "sha256:aaaea1e536f98754a6e5c56091baa1b6ce2f2700cc4a00b0d49eca8dea471074", - "sha256:ad4d7a90a92e528aadf4965d685c17dacff3df282db1121136c382dc0b6014d2", - "sha256:b8477c1ee4bd47c57d49621a062121c3023609f7a13b8a46953eb6c9716ca392", - "sha256:ba6f52cbc7809cd8d74604cce9c14868306ae4aa0282016b641c661f981a6e91", - "sha256:bac8d525a8dbc2a1507ec731d2867025d11ceadcb4dd421423a5d42c56818541", - "sha256:bef596fdaa8f26e3d66af846bbe77057237cb6e8efff8cd7cc8dff9a62278bbf", - "sha256:c0ec0ed476f77db9fb29bca17f0a8fcc7bc97ad4c6c1d8959c507decb22e8572", - "sha256:c38c9ddb6103ceae4e4498f9c08fac9b590c5c71b0370f98714768e22ac6fa66", - "sha256:c7224cab95645c7ab53791022ae77a4509472613e839dab722a72abe5a684575", - "sha256:c74018551e31269d56fab81a728f683667e7c28c04e807ba08f8c9e3bba32f14", - "sha256:ca06675212f94e7a610e85ca36948bb8fc023e458dd6c63ef71abfd482481aa5", - "sha256:d1d2532b340b692880261c15aee4dc94dd22ca5d61b9db9a8a361953d36410b1", - "sha256:d25039a474c4c72a5ad4b52495056f843a7ff07b632c1b92ea9043a3d9950f6e", - "sha256:d5ff2c858f5f6a42c2a8e751100f237c5e869cbde669a724f2062d4c4ef93551", - "sha256:d7d7f7de27b8944f1fee2c26a88b4dabc2409d2fea7a9ed3df79b67277644e17", - "sha256:d7eeb6d22331e2fd42fce928a81c697c9ee2d51400bd1a28803965883e13cead", - "sha256:d8a1c6c0be645c745a081c192e747c5de06e944a0d21245f4cf7c05e457c36e0", - "sha256:d8b889777de69897406c9fb0b76cdf2fd0f31267861ae7501d93003d55f54fbe", - "sha256:d9e09c9d74f4566e905a0b8fa668c58109f7624db96a2171f21747abc7524234", - "sha256:db8e58b9d79200c76956cefd14d5c90af54416ff5353c5bfd7cbe58818e26ef0", - "sha256:ddb2a5c08a4eaaba605340fdee8fc08e406c56617566d9643ad8bf6852778fc7", - "sha256:e0381b4ce23ff92f8170080c97678040fc5b08da85e9e292292aba67fdac6c34", - "sha256:e23a6d84d9d1738dbc6e38167776107e63307dfc8ad108e580548d1f2c587f42", - "sha256:e516dc8baf7b380e6c1c26792610230f37147bb754d6426462ab115a02944385", - "sha256:ea65804b5dc88dacd4a40279af0cdadcfe74b3e5b4c897aa0d81cf86927fee78", - "sha256:ec61d826d80fc293ed46c9dd26995921e3a82146feacd952ef0757236fc137be", - "sha256:ee04010f26d5102399bd17f8df8bc38dc7ccd7701dc77f4a68c5b8d733406958", - "sha256:f3bc6af6e2b8f92eced34ef6a96ffb248e863af20ef4fde9448cc8c9b858b749", - "sha256:f7d6b36dd2e029b6bcb8a13cf19664c7b8e19ab3a58e0fefbb5b8461447ed5ec" + "sha256:0545de8c688fbbf3088f9e8b801157923be4bf8e7b03e97c2ecd4dfa39e48e0e", + "sha256:076b1ed2ac819933895b1a000904f62d615fe4533a5cf3e052ff9a1da560575c", + "sha256:0afad2cd484908f472c8fe2e8ef499facee54a0a6978be0e0cff67b1254fd747", + "sha256:0ccaa1bc98751fbfcf53dc8dfdb90d96e98838010fc254180dd6707a6e8bb179", + "sha256:0d3105efab7c5c091609abacad33afff33bdff0035bece164c98bcf5a85ef90a", + "sha256:0e1af74a9529a1137c67c887ed9cde62cff53aa4d84a3adbec329f9ec47a3936", + "sha256:136f9db0f53c0206db38b8cd0c985c78ded5fd596c9a86ce5c0b92afb91c3a19", + "sha256:156ececdf636143f508770bf8a3a0498de64da5abd890c7dbb42ca9e3b6c05b8", + "sha256:15c87339490100c63472a76d87fe7097a0835c705eb5ae79fd96e343473629ed", + "sha256:1695497bb2a02a6de60064c9f077a4ae9c25c73624e0d43e3aa9d16d983073c2", + "sha256:173563f3696124372831007e3d4b9821746964a95968628f7075d9231ac6bb33", + "sha256:173866d9f7409c0fb514cf6e78952e65816600cb888c68b37b41147349fe0057", + "sha256:23ec1d3c31882b2a8a69c801ef58ebf7bae2553211ebbddf04235be275a38548", + "sha256:243fbbbf003754fe41b5bdf10ce1e7f80bcc70732b5b54222c124d6b4c2ab31c", + "sha256:28c6cf1d92edf936ceedc7afa61b07e9d78a27b15244aa46bbcd534c7458ee1b", + "sha256:2aa738e0282be54eede1e3f36b81f1e46aee7ec7602aa563e81e0e8d7b67963f", + "sha256:2cf441c4b6e538ba0d2591574f95d3fdd33f1efafa864faa077d9636ecc0c4e9", + "sha256:30c3ff305f6e06650a761c4393666f77384f1cc6c5c0251965d6bfa5fbc88f7f", + "sha256:31561a5b4d8dbef1559b3600b045607cf804bae040f64b5f5bca77da38084a8a", + "sha256:32b66be100ac5739065496c74c4b7f3015cef792c3174982809274d7e51b3e04", + "sha256:3433da95b51a75692dcf6cc8117a31410447c75a9a8187888f02ad45c0a86c50", + "sha256:34a2d76a1984cac04ff8b1bfc939ec9dc0914821264d4a9c8fd0ed6aa8d4cfd2", + "sha256:353665775be69bbfc6d54c8d134bfc533e332149faeddd631b0bc79df0897f46", + "sha256:38d0124fa992dbacd0c48b1b755d3ee0a9f924f427f95b0ef376556a24debf01", + "sha256:3c56ec1eacd0a5d35b8a29f468659c47f4fe61b2cab948ca756c39b7617f0aa5", + "sha256:3db817b4e95eb05c362e3b45dafe7144b18603e1211f4a5b36eb9522ecc62bcf", + "sha256:3e52474256a7db9dcf3c5f4ca0b300fdea6c21cca0148c8891d03a025649d935", + "sha256:416f2e3beaeae81e2f7a45dc711258be5bdc79c940a9a270b266c0bec038fb84", + "sha256:435aca062444a7f0c884861d2e3ea79883bd1cd19d0a381928b69ae1b85bc51d", + "sha256:4388c72174868884f76affcdd3656544c426407e0043c89b684d22fb265e04a5", + "sha256:43ebdcc120e2ca679dba01a779333a8ea76b50547b55e812b8b92818d604662c", + "sha256:458c0c65802d816a6b955cf3603186de79e8fdb46d4f19abaec4ef0a906f50a7", + "sha256:533a28754e7f7439f217550a497bb026c54072dbe16402b183fdbca2431935a9", + "sha256:553dad9af802a9ad1a6525e7528152a015b85fb8dbf764ebfc755c695f488367", + "sha256:5838f2b79dc8f96fdc44077c9e4e2e33d7089b10788464609df788eb97d03aad", + "sha256:5b48388ded01f6f2429a8c55012bdbd1c2a0c3735b3e73e221649e524c34a58d", + "sha256:5bc0df728e4def5e15a754521e8882ba5a5121bd6b5a3a0ff7efda5d6558ab3d", + "sha256:63eab904f8630aed5a68f2d0aeab565dcfc595dc1bf0b91b71d9ddd43dea3aea", + "sha256:66f629632220a4e7858b58e4857927dd01a850a4cef2fb4044c8662787165cf7", + "sha256:670eb11325ed3a6209339974b276811867defe52f4188fe18dc49855774fa9cf", + "sha256:69d5856d526802cbda768d3e6246cd0d77450fa2a4bc2ea0ea14f0d972c2894b", + "sha256:6e840553c9c494a35e449a987ca2c4f8372668ee954a03a9a9685075228e5036", + "sha256:711bdfae4e699a6d4f371137cbe9e740dc958530cb920eb6f43ff9551e17cfbc", + "sha256:74abb8709ea54cc483c4fb57fb17bb66f8e0f04438cff6ded322074dbd17c7ec", + "sha256:75119badf45f7183e10e348edff5a76a94dc19ba9287d94001ff05e81475967b", + "sha256:766dcc00b943c089349d4060b935c76281f6be225e39994c2ccec3a2a36ad627", + "sha256:78e6fdc976ec966b99e4daa3812fac0274cc28cd2b24b0d92462e2e5ef90d368", + "sha256:81dadafb3aa124f86dc267a2168f71bbd2bfb163663661ab0038f6e4b8edb810", + "sha256:82d5161e8cb8f36ec778fd7ac4d740415d84030f5b9ef8fe4da54784a1f46c94", + "sha256:833547179c31f9bec39b49601d282d6f0ea1633620701288934c5f66d88c3e50", + "sha256:856b7f1a7b98a8c31823285786bd566cf06226ac4f38b3ef462f593c608a9bd6", + "sha256:8657d3f37f781d987037f9cc20bbc8b40425fa14380c87da0cb8dfce7c92d0fb", + "sha256:93bed8a8084544c6efe8856c362af08a23e959340c87a95687fdbe9c9f280c8b", + "sha256:954dde77c404084c2544e572f342aef384240b3e434e06cecc71597e95fd1ce7", + "sha256:98f68df80ec6ca3015186b2677c208c096d646ef37bbf8b49764ab4a38183931", + "sha256:99e12d2bf587b44deb74e0d6170fec37adb489964dbca656ec41a7cd8f2ff178", + "sha256:9a13a07532e8e1c4a5a3afff0ca4553da23409fad65def1b71186fb867eeae8d", + "sha256:9c1e3ff4b89cdd2e1a24c214f141e848b9e0451f08d7d4963cb4108d4d798f1f", + "sha256:9ce2e0f6123a60bd1a7f5ae3b2c49b240c12c132847f17aa990b841a417598a2", + "sha256:9fcda20b2de7042cc35cf911702fa3d8311bd40055a14446c1e62403684afdc5", + "sha256:a32d58f4b521bb98b2c0aa9da407f8bd57ca81f34362bcb090e4a79e9924fefc", + "sha256:a39c36f4218a5bb668b4f06874d676d35a035ee668e6e7e3538835c703634b84", + "sha256:a5cafb02cf097a82d74403f7e0b6b9df3ffbfe8edf9415ea816314711764a27b", + "sha256:a7cf963a357c5f00cb55b1955df8bbe68d2f2f65de065160a1c26b85a1e44172", + "sha256:a880372e2e5dbb9258a4e8ff43f13888039abb9dd6d515f28611c54361bc5644", + "sha256:ace4cad790f3bf872c082366c9edd7f8f8f77afe3992b134cfc810332206884f", + "sha256:af8ff8d7dc07ce873f643de6dfbcd45dc3db2c87462e5c387267197f59e6d776", + "sha256:b47a6000a7e833ebfe5886b56a31cb2ff12120b1efd4578a6fcc38df16cc77bd", + "sha256:b71862a652f50babab4a43a487f157d26b464b1dedbcc0afda02fd64f3809d04", + "sha256:b7f227ca6db5a9fda0a2b935a2ea34a7267589ffc63c8045f0e4edb8d8dcf956", + "sha256:bc8936d06cd53fddd4892677d65e98af514c8d78c79864f418bbf78a4a2edde4", + "sha256:bed1b5dbf90bad3bfc19439258c97873eab453c71d8b6869c136346acfe497e7", + "sha256:c45817e3e6972109d1a2c65091504a537e257bc3c885b4e78a95baa96df6a3f8", + "sha256:c68e820879ff39992c7f148113b46efcd6ec765a4865581f2902b3c43a5f4bbb", + "sha256:c77494a2f2282d9bbbbcab7c227a4d1b4bb829875c96251f66fb5f3bae4fb053", + "sha256:c998d0558805860503bc3a595994895ca0f7835e00668dadc673bbf7f5fbfcbe", + "sha256:ccad2800dfdff34392448c4bf834be124f10a5bc102f254521d931c1c53c455a", + "sha256:cd126498171f752dd85737ab1544329a4520c53eed3997f9b08aefbafb1cc53b", + "sha256:ce44217ad99ffad8027d2fde0269ae368c86db66ea0571c62a000798d69401fb", + "sha256:d1ac2bc069f4a458634c26b101c2341b18da85cb96afe0015990507efec2e417", + "sha256:d417a4f6943112fae3924bae2af7112562285848d9bcee737fc4ff7cbd450e6c", + "sha256:d538df442c0d9665664ab6dd5fccd0110fa3b364914f9c85b3ef9b7b2e157980", + "sha256:ded1b1803151dd0f20a8945508786d57c2f97a50289b16f2629f85433e546d47", + "sha256:e2e93b88ecc8f74074012e18d679fb2e9c746f2a56f79cd5e2b1afcf2a8a786b", + "sha256:e4ca3b9f370f218cc2a0309542cab8d0acdfd66667e7c37d04d617012485f904", + "sha256:e4ee8b8639070ff246ad3649294336b06db37a94bdea0d09ea491603e0be73b8", + "sha256:e52f77a0cd246086afde8815039f3e16f8d2be51786c0a39b57104c563c5cbb0", + "sha256:eaea112aed589131f73d50d570a6864728bd7c0c66ef6c9154ed7b59f24da611", + "sha256:ed20a4bdc635f36cb19e630bfc644181dd075839b6fc84cac51c0f381ac472e2", + "sha256:eedc3f247ee7b3808ea07205f3e7d7879bc19ad3e6222195cd5fbf9988853e4d", + "sha256:f0e1844ad47c7bd5d6fa784f1d4accc5f4168b48999303a868fe0f8597bde715", + "sha256:f4fe99ce44128c71233d0d72152db31ca119711dfc5f2c82385ad611d8d7f897", + "sha256:f8cfd847e6b9ecf9f2f2531c8427035f291ec286c0a4944b0a9fce58c6446046", + "sha256:f9ca0e6ce7774dc7830dc0cc4bb6b3eec769db667f230e7c770a628c1aa5681b", + "sha256:fa2bea05ff0a8fb4d8124498e00e02398f06d23cdadd0fe027d84a3f7afde31e", + "sha256:fbbb63bed5fcd70cd3dd23a087cd78e4675fb5a2963b8af53f945cbbca79ae16", + "sha256:fbda058a9a68bec347962595f50546a8a4a34fd7b0654a7b9697917dc2bf810d", + "sha256:ffd591e22b22f9cb48e472529db6a47203c41c2c5911ff0a52e85723196c0d75" ], - "markers": "python_version >= '3.7'", - "version": "==1.9.4" + "markers": "python_version >= '3.8'", + "version": "==1.15.2" } }, "develop": { + "certifi": { + "hashes": [ + "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8", + "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9" + ], + "markers": "python_version >= '3.6'", + "version": "==2024.8.30" + }, + "charset-normalizer": { + "hashes": [ + "sha256:0099d79bdfcf5c1f0c2c72f91516702ebf8b0b8ddd8905f97a8aecf49712c621", + "sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6", + "sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8", + "sha256:0b309d1747110feb25d7ed6b01afdec269c647d382c857ef4663bbe6ad95a912", + "sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c", + "sha256:0de7b687289d3c1b3e8660d0741874abe7888100efe14bd0f9fd7141bcbda92b", + "sha256:1110e22af8ca26b90bd6364fe4c763329b0ebf1ee213ba32b68c73de5752323d", + "sha256:130272c698667a982a5d0e626851ceff662565379baf0ff2cc58067b81d4f11d", + "sha256:136815f06a3ae311fae551c3df1f998a1ebd01ddd424aa5603a4336997629e95", + "sha256:14215b71a762336254351b00ec720a8e85cada43b987da5a042e4ce3e82bd68e", + "sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565", + "sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64", + "sha256:2006769bd1640bdf4d5641c69a3d63b71b81445473cac5ded39740a226fa88ab", + "sha256:20587d20f557fe189b7947d8e7ec5afa110ccf72a3128d61a2a387c3313f46be", + "sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e", + "sha256:27623ba66c183eca01bf9ff833875b459cad267aeeb044477fedac35e19ba907", + "sha256:285e96d9d53422efc0d7a17c60e59f37fbf3dfa942073f666db4ac71e8d726d0", + "sha256:2de62e8801ddfff069cd5c504ce3bc9672b23266597d4e4f50eda28846c322f2", + "sha256:2f6c34da58ea9c1a9515621f4d9ac379871a8f21168ba1b5e09d74250de5ad62", + "sha256:309a7de0a0ff3040acaebb35ec45d18db4b28232f21998851cfa709eeff49d62", + "sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23", + "sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc", + "sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284", + "sha256:40d3ff7fc90b98c637bda91c89d51264a3dcf210cade3a2c6f838c7268d7a4ca", + "sha256:425c5f215d0eecee9a56cdb703203dda90423247421bf0d67125add85d0c4455", + "sha256:43193c5cda5d612f247172016c4bb71251c784d7a4d9314677186a838ad34858", + "sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b", + "sha256:47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594", + "sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc", + "sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db", + "sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b", + "sha256:4ec9dd88a5b71abfc74e9df5ebe7921c35cbb3b641181a531ca65cdb5e8e4dea", + "sha256:4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6", + "sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920", + "sha256:55f56e2ebd4e3bc50442fbc0888c9d8c94e4e06a933804e2af3e89e2f9c1c749", + "sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7", + "sha256:5d447056e2ca60382d460a604b6302d8db69476fd2015c81e7c35417cfabe4cd", + "sha256:5ed2e36c3e9b4f21dd9422f6893dec0abf2cca553af509b10cd630f878d3eb99", + "sha256:5ff2ed8194587faf56555927b3aa10e6fb69d931e33953943bc4f837dfee2242", + "sha256:62f60aebecfc7f4b82e3f639a7d1433a20ec32824db2199a11ad4f5e146ef5ee", + "sha256:63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129", + "sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2", + "sha256:6b493a043635eb376e50eedf7818f2f322eabbaa974e948bd8bdd29eb7ef2a51", + "sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee", + "sha256:6fd30dc99682dc2c603c2b315bded2799019cea829f8bf57dc6b61efde6611c8", + "sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b", + "sha256:7706f5850360ac01d80c89bcef1640683cc12ed87f42579dab6c5d3ed6888613", + "sha256:7782afc9b6b42200f7362858f9e73b1f8316afb276d316336c0ec3bd73312742", + "sha256:79983512b108e4a164b9c8d34de3992f76d48cadc9554c9e60b43f308988aabe", + "sha256:7f683ddc7eedd742e2889d2bfb96d69573fde1d92fcb811979cdb7165bb9c7d3", + "sha256:82357d85de703176b5587dbe6ade8ff67f9f69a41c0733cf2425378b49954de5", + "sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631", + "sha256:86f4e8cca779080f66ff4f191a685ced73d2f72d50216f7112185dc02b90b9b7", + "sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15", + "sha256:8ce7fd6767a1cc5a92a639b391891bf1c268b03ec7e021c7d6d902285259685c", + "sha256:8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea", + "sha256:9289fd5dddcf57bab41d044f1756550f9e7cf0c8e373b8cdf0ce8773dc4bd417", + "sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250", + "sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88", + "sha256:95c3c157765b031331dd4db3c775e58deaee050a3042fcad72cbc4189d7c8dca", + "sha256:980b4f289d1d90ca5efcf07958d3eb38ed9c0b7676bf2831a54d4f66f9c27dfa", + "sha256:9ae4ef0b3f6b41bad6366fb0ea4fc1d7ed051528e113a60fa2a65a9abb5b1d99", + "sha256:9c98230f5042f4945f957d006edccc2af1e03ed5e37ce7c373f00a5a4daa6149", + "sha256:9fa2566ca27d67c86569e8c85297aaf413ffab85a8960500f12ea34ff98e4c41", + "sha256:a14969b8691f7998e74663b77b4c36c0337cb1df552da83d5c9004a93afdb574", + "sha256:a8aacce6e2e1edcb6ac625fb0f8c3a9570ccc7bfba1f63419b3769ccf6a00ed0", + "sha256:a8e538f46104c815be19c975572d74afb53f29650ea2025bbfaef359d2de2f7f", + "sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d", + "sha256:aa693779a8b50cd97570e5a0f343538a8dbd3e496fa5dcb87e29406ad0299654", + "sha256:ab22fbd9765e6954bc0bcff24c25ff71dcbfdb185fcdaca49e81bac68fe724d3", + "sha256:ab2e5bef076f5a235c3774b4f4028a680432cded7cad37bba0fd90d64b187d19", + "sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90", + "sha256:af73657b7a68211996527dbfeffbb0864e043d270580c5aef06dc4b659a4b578", + "sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9", + "sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1", + "sha256:b8831399554b92b72af5932cdbbd4ddc55c55f631bb13ff8fe4e6536a06c5c51", + "sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719", + "sha256:bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236", + "sha256:bd7af3717683bea4c87acd8c0d3d5b44d56120b26fd3f8a692bdd2d5260c620a", + "sha256:bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c", + "sha256:c3e446d253bd88f6377260d07c895816ebf33ffffd56c1c792b13bff9c3e1ade", + "sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944", + "sha256:c94057af19bc953643a33581844649a7fdab902624d2eb739738a30e2b3e60fc", + "sha256:cab5d0b79d987c67f3b9e9c53f54a61360422a5a0bc075f43cab5621d530c3b6", + "sha256:ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6", + "sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27", + "sha256:d5b054862739d276e09928de37c79ddeec42a6e1bfc55863be96a36ba22926f6", + "sha256:dbe03226baf438ac4fda9e2d0715022fd579cb641c4cf639fa40d53b2fe6f3e2", + "sha256:dc15e99b2d8a656f8e666854404f1ba54765871104e50c8e9813af8a7db07f12", + "sha256:dcaf7c1524c0542ee2fc82cc8ec337f7a9f7edee2532421ab200d2b920fc97cf", + "sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114", + "sha256:dd9a8bd8900e65504a305bf8ae6fa9fbc66de94178c420791d0293702fce2df7", + "sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf", + "sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d", + "sha256:e91f541a85298cf35433bf66f3fab2a4a2cff05c127eeca4af174f6d497f0d4b", + "sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed", + "sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03", + "sha256:f09cb5a7bbe1ecae6e87901a2eb23e0256bb524a79ccc53eb0b7629fbe7677c4", + "sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67", + "sha256:f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365", + "sha256:f28f891ccd15c514a0981f3b9db9aa23d62fe1a99997512b0491d2ed323d229a", + "sha256:f3e73a4255342d4eb26ef6df01e3962e73aa29baa3124a8e824c5d3364a65748", + "sha256:f606a1881d2663630ea5b8ce2efe2111740df4b687bd78b34a8131baa007f79b", + "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079", + "sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482" + ], + "markers": "python_full_version >= '3.7.0'", + "version": "==3.4.0" + }, "coverage": { "hashes": [ - "sha256:018a12985185038a5b2bcafab04ab833a9a0f2c59995b3cec07e10074c78635f", - "sha256:02ff6e898197cc1e9fa375581382b72498eb2e6d5fc0b53f03e496cfee3fac6d", - "sha256:042183de01f8b6d531e10c197f7f0315a61e8d805ab29c5f7b51a01d62782747", - "sha256:1014fbf665fef86cdfd6cb5b7371496ce35e4d2a00cda501cf9f5b9e6fced69f", - "sha256:1137f46adb28e3813dec8c01fefadcb8c614f33576f672962e323b5128d9a68d", - "sha256:16852febd96acd953b0d55fc842ce2dac1710f26729b31c80b940b9afcd9896f", - "sha256:2174e7c23e0a454ffe12267a10732c273243b4f2d50d07544a91198f05c48f47", - "sha256:2214ee920787d85db1b6a0bd9da5f8503ccc8fcd5814d90796c2f2493a2f4d2e", - "sha256:3257fdd8e574805f27bb5342b77bc65578e98cbc004a92232106344053f319ba", - "sha256:3684bc2ff328f935981847082ba4fdc950d58906a40eafa93510d1b54c08a66c", - "sha256:3a6612c99081d8d6134005b1354191e103ec9705d7ba2754e848211ac8cacc6b", - "sha256:3d7564cc09dd91b5a6001754a5b3c6ecc4aba6323baf33a12bd751036c998be4", - "sha256:44da56a2589b684813f86d07597fdf8a9c6ce77f58976727329272f5a01f99f7", - "sha256:5013ed890dc917cef2c9f765c4c6a8ae9df983cd60dbb635df8ed9f4ebc9f555", - "sha256:54317c2b806354cbb2dc7ac27e2b93f97096912cc16b18289c5d4e44fc663233", - "sha256:56b4eafa21c6c175b3ede004ca12c653a88b6f922494b023aeb1e836df953ace", - "sha256:581ea96f92bf71a5ec0974001f900db495488434a6928a2ca7f01eee20c23805", - "sha256:5cd64adedf3be66f8ccee418473c2916492d53cbafbfcff851cbec5a8454b136", - "sha256:5df54843b88901fdc2f598ac06737f03d71168fd1175728054c8f5a2739ac3e4", - "sha256:65e528e2e921ba8fd67d9055e6b9f9e34b21ebd6768ae1c1723f4ea6ace1234d", - "sha256:6aae5cce399a0f065da65c7bb1e8abd5c7a3043da9dceb429ebe1b289bc07806", - "sha256:6cfb5a4f556bb51aba274588200a46e4dd6b505fb1a5f8c5ae408222eb416f99", - "sha256:7076b4b3a5f6d2b5d7f1185fde25b1e54eb66e647a1dfef0e2c2bfaf9b4c88c8", - "sha256:73ca8fbc5bc622e54627314c1a6f1dfdd8db69788f3443e752c215f29fa87a0b", - "sha256:79b356f3dd5b26f3ad23b35c75dbdaf1f9e2450b6bcefc6d0825ea0aa3f86ca5", - "sha256:7a892be37ca35eb5019ec85402c3371b0f7cda5ab5056023a7f13da0961e60da", - "sha256:8192794d120167e2a64721d88dbd688584675e86e15d0569599257566dec9bf0", - "sha256:820bc841faa502e727a48311948e0461132a9c8baa42f6b2b84a29ced24cc078", - "sha256:8f894208794b164e6bd4bba61fc98bf6b06be4d390cf2daacfa6eca0a6d2bb4f", - "sha256:a04e990a2a41740b02d6182b498ee9796cf60eefe40cf859b016650147908029", - "sha256:a44963520b069e12789d0faea4e9fdb1e410cdc4aab89d94f7f55cbb7fef0353", - "sha256:a6bb74ed465d5fb204b2ec41d79bcd28afccf817de721e8a807d5141c3426638", - "sha256:ab73b35e8d109bffbda9a3e91c64e29fe26e03e49addf5b43d85fc426dde11f9", - "sha256:aea072a941b033813f5e4814541fc265a5c12ed9720daef11ca516aeacd3bd7f", - "sha256:b1ccf5e728ccf83acd313c89f07c22d70d6c375a9c6f339233dcf792094bcbf7", - "sha256:b385d49609f8e9efc885790a5a0e89f2e3ae042cdf12958b6034cc442de428d3", - "sha256:b3d45ff86efb129c599a3b287ae2e44c1e281ae0f9a9bad0edc202179bcc3a2e", - "sha256:b4a474f799456e0eb46d78ab07303286a84a3140e9700b9e154cfebc8f527016", - "sha256:b95c3a8cb0463ba9f77383d0fa8c9194cf91f64445a63fc26fb2327e1e1eb088", - "sha256:c5986ee7ea0795a4095ac4d113cbb3448601efca7f158ec7f7087a6c705304e4", - "sha256:cdd31315fc20868c194130de9ee6bfd99755cc9565edff98ecc12585b90be882", - "sha256:cef4649ec906ea7ea5e9e796e68b987f83fa9a718514fe147f538cfeda76d7a7", - "sha256:d05c16cf4b4c2fc880cb12ba4c9b526e9e5d5bb1d81313d4d732a5b9fe2b9d53", - "sha256:d2e344d6adc8ef81c5a233d3a57b3c7d5181f40e79e05e1c143da143ccb6377d", - "sha256:d45d3cbd94159c468b9b8c5a556e3f6b81a8d1af2a92b77320e887c3e7a5d080", - "sha256:db14f552ac38f10758ad14dd7b983dbab424e731588d300c7db25b6f89e335b5", - "sha256:dbc5958cb471e5a5af41b0ddaea96a37e74ed289535e8deca404811f6cb0bc3d", - "sha256:ddbd2f9713a79e8e7242d7c51f1929611e991d855f414ca9996c20e44a895f7c", - "sha256:e16f3d6b491c48c5ae726308e6ab1e18ee830b4cdd6913f2d7f77354b33f91c8", - "sha256:e2afe743289273209c992075a5a4913e8d007d569a406ffed0bd080ea02b0633", - "sha256:e564c2cf45d2f44a9da56f4e3a26b2236504a496eb4cb0ca7221cd4cc7a9aca9", - "sha256:ed550e7442f278af76d9d65af48069f1fb84c9f745ae249c1a183c1e9d1b025c" + "sha256:04f2189716e85ec9192df307f7c255f90e78b6e9863a03223c3b998d24a3c6c6", + "sha256:0c6c0f4d53ef603397fc894a895b960ecd7d44c727df42a8d500031716d4e8d2", + "sha256:0ca37993206402c6c35dc717f90d4c8f53568a8b80f0bf1a1b2b334f4d488fba", + "sha256:12f9515d875859faedb4144fd38694a761cd2a61ef9603bf887b13956d0bbfbb", + "sha256:1990b1f4e2c402beb317840030bb9f1b6a363f86e14e21b4212e618acdfce7f6", + "sha256:2341a78ae3a5ed454d524206a3fcb3cec408c2a0c7c2752cd78b606a2ff15af4", + "sha256:23bb63ae3f4c645d2d82fa22697364b0046fbafb6261b258a58587441c5f7bd0", + "sha256:27bd5f18d8f2879e45724b0ce74f61811639a846ff0e5c0395b7818fae87aec6", + "sha256:2dc7d6b380ca76f5e817ac9eef0c3686e7834c8346bef30b041a4ad286449990", + "sha256:331b200ad03dbaa44151d74daeb7da2cf382db424ab923574f6ecca7d3b30de3", + "sha256:365defc257c687ce3e7d275f39738dcd230777424117a6c76043459db131dd43", + "sha256:37be7b5ea3ff5b7c4a9db16074dc94523b5f10dd1f3b362a827af66a55198175", + "sha256:3c2e6fa98032fec8282f6b27e3f3986c6e05702828380618776ad794e938f53a", + "sha256:40e8b1983080439d4802d80b951f4a93d991ef3261f69e81095a66f86cf3c3c6", + "sha256:43517e1f6b19f610a93d8227e47790722c8bf7422e46b365e0469fc3d3563d97", + "sha256:43b32a06c47539fe275106b376658638b418c7cfdfff0e0259fbf877e845f14b", + "sha256:43d6a66e33b1455b98fc7312b124296dad97a2e191c80320587234a77b1b736e", + "sha256:4c59d6a4a4633fad297f943c03d0d2569867bd5372eb5684befdff8df8522e39", + "sha256:52ac29cc72ee7e25ace7807249638f94c9b6a862c56b1df015d2b2e388e51dbd", + "sha256:54356a76b67cf8a3085818026bb556545ebb8353951923b88292556dfa9f812d", + "sha256:583049c63106c0555e3ae3931edab5669668bbef84c15861421b94e121878d3f", + "sha256:6d99198203f0b9cb0b5d1c0393859555bc26b548223a769baf7e321a627ed4fc", + "sha256:6da42bbcec130b188169107ecb6ee7bd7b4c849d24c9370a0c884cf728d8e976", + "sha256:6e484e479860e00da1f005cd19d1c5d4a813324e5951319ac3f3eefb497cc549", + "sha256:70a6756ce66cd6fe8486c775b30889f0dc4cb20c157aa8c35b45fd7868255c5c", + "sha256:70d24936ca6c15a3bbc91ee9c7fc661132c6f4c9d42a23b31b6686c05073bde5", + "sha256:71967c35828c9ff94e8c7d405469a1fb68257f686bca7c1ed85ed34e7c2529c4", + "sha256:79644f68a6ff23b251cae1c82b01a0b51bc40c8468ca9585c6c4b1aeee570e0b", + "sha256:87cd2e29067ea397a47e352efb13f976eb1b03e18c999270bb50589323294c6e", + "sha256:8d4c6ea0f498c7c79111033a290d060c517853a7bcb2f46516f591dab628ddd3", + "sha256:9134032f5aa445ae591c2ba6991d10136a1f533b1d2fa8f8c21126468c5025c6", + "sha256:921fbe13492caf6a69528f09d5d7c7d518c8d0e7b9f6701b7719715f29a71e6e", + "sha256:99670790f21a96665a35849990b1df447993880bb6463a0a1d757897f30da929", + "sha256:9975442f2e7a5cfcf87299c26b5a45266ab0696348420049b9b94b2ad3d40234", + "sha256:99ded130555c021d99729fabd4ddb91a6f4cc0707df4b1daf912c7850c373b13", + "sha256:a3328c3e64ea4ab12b85999eb0779e6139295bbf5485f69d42cf794309e3d007", + "sha256:a4fb91d5f72b7e06a14ff4ae5be625a81cd7e5f869d7a54578fc271d08d58ae3", + "sha256:aa23ce39661a3e90eea5f99ec59b763b7d655c2cada10729ed920a38bfc2b167", + "sha256:aac7501ae73d4a02f4b7ac8fcb9dc55342ca98ffb9ed9f2dfb8a25d53eda0e4d", + "sha256:ab84a8b698ad5a6c365b08061920138e7a7dd9a04b6feb09ba1bfae68346ce6d", + "sha256:b4adeb878a374126f1e5cf03b87f66279f479e01af0e9a654cf6d1509af46c40", + "sha256:b9853509b4bf57ba7b1f99b9d866c422c9c5248799ab20e652bbb8a184a38181", + "sha256:bb7d5fe92bd0dc235f63ebe9f8c6e0884f7360f88f3411bfed1350c872ef2054", + "sha256:bca4c8abc50d38f9773c1ec80d43f3768df2e8576807d1656016b9d3eeaa96fd", + "sha256:c222958f59b0ae091f4535851cbb24eb57fc0baea07ba675af718fb5302dddb2", + "sha256:c30e42ea11badb147f0d2e387115b15e2bd8205a5ad70d6ad79cf37f6ac08c91", + "sha256:c3a79f56dee9136084cf84a6c7c4341427ef36e05ae6415bf7d787c96ff5eaa3", + "sha256:c51ef82302386d686feea1c44dbeef744585da16fcf97deea2a8d6c1556f519b", + "sha256:c77326300b839c44c3e5a8fe26c15b7e87b2f32dfd2fc9fee1d13604347c9b38", + "sha256:d33a785ea8354c480515e781554d3be582a86297e41ccbea627a5c632647f2cd", + "sha256:d546cfa78844b8b9c1c0533de1851569a13f87449897bbc95d698d1d3cb2a30f", + "sha256:da29ceabe3025a1e5a5aeeb331c5b1af686daab4ff0fb4f83df18b1180ea83e2", + "sha256:df8c05a0f574d480947cba11b947dc41b1265d721c3777881da2fb8d3a1ddfba", + "sha256:e266af4da2c1a4cbc6135a570c64577fd3e6eb204607eaff99d8e9b710003c6f", + "sha256:e279f3db904e3b55f520f11f983cc8dc8a4ce9b65f11692d4718ed021ec58b83", + "sha256:ea52bd218d4ba260399a8ae4bb6b577d82adfc4518b93566ce1fddd4a49d1dce", + "sha256:ebec65f5068e7df2d49466aab9128510c4867e532e07cb6960075b27658dca38", + "sha256:ec1e3b40b82236d100d259854840555469fad4db64f669ab817279eb95cd535c", + "sha256:ee77c7bef0724165e795b6b7bf9c4c22a9b8468a6bdb9c6b4281293c6b22a90f", + "sha256:f263b18692f8ed52c8de7f40a0751e79015983dbd77b16906e5b310a39d3ca21", + "sha256:f7b26757b22faf88fcf232f5f0e62f6e0fd9e22a8a5d0d5016888cdfe1f6c1c4", + "sha256:f7ddb920106bbbbcaf2a274d56f46956bf56ecbde210d88061824a95bdd94e92" ], "index": "pypi", - "version": "==7.5.4" + "markers": "python_version >= '3.9'", + "version": "==7.6.3" + }, + "idna": { + "hashes": [ + "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", + "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3" + ], + "markers": "python_version >= '3.6'", + "version": "==3.10" }, "iniconfig": { "hashes": [ @@ -1654,11 +2015,37 @@ }, "pytest": { "hashes": [ - "sha256:c434598117762e2bd304e526244f67bf66bbd7b5d6cf22138be51ff661980343", - "sha256:de4bb8104e201939ccdc688b27a89a7be2079b22e2bd2b07f806b6ba71117977" + "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181", + "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2" ], "index": "pypi", - "version": "==8.2.2" + "markers": "python_version >= '3.8'", + "version": "==8.3.3" + }, + "requests": { + "hashes": [ + "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", + "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6" + ], + "markers": "python_version >= '3.8'", + "version": "==2.32.3" + }, + "requests-mock": { + "hashes": [ + "sha256:b1e37054004cdd5e56c84454cc7df12b25f90f382159087f4b6915aaeef39563", + "sha256:e9e12e333b525156e82a3c852f22016b9158220d2f47454de9cae8a77d371401" + ], + "index": "pypi", + "markers": "python_version >= '3.5'", + "version": "==1.12.1" + }, + "urllib3": { + "hashes": [ + "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac", + "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9" + ], + "markers": "python_version >= '3.10'", + "version": "==2.2.3" } } } diff --git a/dbrepo-search-service/app.py b/dbrepo-search-service/app.py index f8d7856c9b7f7c60cf9769e3ade9f800640f0b9f..7566178526d97cd7e21a288edd1d9881e49ad9cc 100644 --- a/dbrepo-search-service/app.py +++ b/dbrepo-search-service/app.py @@ -2,6 +2,7 @@ import math import os import logging from ast import literal_eval +from json import dumps from typing import List, Any import requests @@ -10,6 +11,7 @@ from flasgger import LazyJSONEncoder, Swagger, swag_from from flask import Flask, request from flask_cors import CORS from flask_httpauth import HTTPTokenAuth, HTTPBasicAuth, MultiAuth +from jwt.exceptions import JWTDecodeError from opensearchpy import TransportError, NotFoundError from prometheus_flask_exporter import PrometheusMetrics from pydantic import ValidationError @@ -165,7 +167,7 @@ template = { "info": { "title": "Database Repository Search Service API", "description": "Service that searches the search database", - "version": "1.4.5", + "version": "1.4.7", "contact": { "name": "Prof. Andreas Rauber", "email": "andreas.rauber@tuwien.ac.at" @@ -177,7 +179,7 @@ template = { }, "externalDocs": { "description": "Sourcecode Documentation", - "url": "https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.4.5/" + "url": "https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.4.7/" }, "servers": [ { @@ -206,9 +208,6 @@ app.config["OPENSEARCH_PASSWORD"] = os.getenv('OPENSEARCH_PASSWORD', 'admin') app.json_encoder = LazyJSONEncoder -available_types = literal_eval( - os.getenv("COLLECTION", "['database','table','column','identifier','unit','concept','user','view']")) - @token_auth.verify_token def verify_token(token: str): @@ -217,7 +216,7 @@ def verify_token(token: str): try: client = KeycloakClient() return client.verify_jwt(access_token=token) - except AssertionError: + except JWTDecodeError as error: return False @@ -268,8 +267,7 @@ def general_filter(index, results): "view": ["id", "name", "creator", " created"], } if index not in important_keys.keys(): - error_msg = "the keys to be returned to the user for your index aren't specified in the important Keys dict" - raise KeyError(error_msg) + raise KeyError(f"Failed to find index {index} in: {important_keys.keys()}") for result in results: result_keys_copy = tuple(result.keys()) for key in result_keys_copy: @@ -294,35 +292,37 @@ def get_index(index: str): :return: list of the results """ logging.info(f'Searching for index: {index}') - if index not in available_types: - return ApiError(status='NOT_FOUND', message='Failed to find index', - code='search.index.missing').model_dump(), 404 results = OpenSearchClient().query_index_by_term_opensearch("*", "contains") - results = general_filter(index, results) - - results_per_page = min(request.args.get("results_per_page", 50, type=int), 500) - max_pages = math.ceil(len(results) / results_per_page) - page = min(request.args.get("page", 1, type=int), max_pages) - results = results[(results_per_page * (page - 1)): (results_per_page * page)] - return dict({"results": results}), 200 + try: + results = general_filter(index, results) + + results_per_page = min(request.args.get("results_per_page", 50, type=int), 500) + max_pages = math.ceil(len(results) / results_per_page) + page = min(request.args.get("page", 1, type=int), max_pages) + results = results[(results_per_page * (page - 1)): (results_per_page * page)] + return dict({"results": results}), 200 + except KeyError: + return ApiError(status='NOT_FOUND', message=f'Failed to find get index: {index}', + code='search.index.missing').model_dump(), 404 -@app.route("/api/search/<string:type>/fields", methods=["GET"], endpoint="search_get_index_fields") +@app.route("/api/search/<string:field_type>/fields", methods=["GET"], endpoint="search_get_index_fields") @metrics.gauge(name='dbrepo_search_type_list', description='Time needed to list search types') @swag_from("os-yml/get_fields.yml") -def get_fields(type: str): +def get_fields(field_type: str): """ returns a list of attributes of the data for a specific index. - :param type: The search type + :param field_type: The search type :return: """ - logging.info(f'Searching in index database for type: {type}') - if type not in available_types: - return ApiError(status='NOT_FOUND', message='Failed to find type', + logging.info(f'Searching in index database for type: {field_type}') + try: + fields = OpenSearchClient().get_fields_for_index(field_type) + logging.debug(f'get fields for field_type {field_type} resulted in {len(fields)} field(s)') + return fields, 200 + except NotFoundError: + return ApiError(status='NOT_FOUND', message=f'Failed to find fields for search type {field_type}', code='search.type.missing').model_dump(), 404 - fields = OpenSearchClient().get_fields_for_index(type) - logging.debug(f'get fields for type {type} resulted in {len(fields)} field(s)') - return fields, 200 @app.route("/api/search", methods=["GET"], endpoint="search_fuzzy_search") @@ -344,10 +344,10 @@ def get_fuzzy_search(): return dict({"results": results}), 200 -@app.route("/api/search/<string:type>", methods=["POST"], endpoint="search_post_general_search") +@app.route("/api/search/<string:field_type>", methods=["POST"], endpoint="search_post_general_search") @metrics.gauge(name='dbrepo_search_type', description='Time needed to search by type') @swag_from("os-yml/post_general_search.yml") -def post_general_search(type): +def post_general_search(field_type): """ Main endpoint for fuzzy searching. :return: @@ -356,11 +356,7 @@ def post_general_search(type): return ApiError(status='UNSUPPORTED_MEDIA_TYPE', message='Content type needs to be application/json', code='search.general.media').model_dump(), 415 req_body = request.json - logging.info(f'Searching in index database for type: {type}') - logging.debug(f"search request body: {req_body}") - if type is not None and type not in available_types: - return ApiError(status='NOT_FOUND', message=f'Type {type} is not in collection: {available_types}', - code='search.general.missing').model_dump(), 404 + logging.info(f'Searching in index database for type: {field_type}') t1 = request.args.get("t1") if not str(t1).isdigit(): t1 = None @@ -370,9 +366,9 @@ def post_general_search(type): if t1 is not None and t2 is not None and "unit.uri" in req_body and "concept.uri" in req_body: response = OpenSearchClient().unit_independent_search(t1, t2, req_body) else: - response = OpenSearchClient().general_search(type, req_body) + response = OpenSearchClient().general_search(field_type, req_body) # filter by type - if type == 'table': + if field_type == 'table': tmp = [] for database in response: if database["tables"] is not None: @@ -380,7 +376,7 @@ def post_general_search(type): table["is_public"] = database["is_public"] tmp.append(table) response = tmp - if type == 'identifier': + if field_type == 'identifier': tmp = [] for database in response: if database["identifiers"] is not None: @@ -398,30 +394,30 @@ def post_general_search(type): if 'identifier' in view: tmp.append(view['identifier']) response = tmp - elif type == 'column': + elif field_type == 'column': response = [x for xs in response for x in xs["tables"]] for table in response: for column in table["columns"]: column["table_id"] = table["id"] column["database_id"] = table["database_id"] response = [x for xs in response for x in xs["columns"]] - elif type == 'concept': + elif field_type == 'concept': tmp = [] tables = [x for xs in response for x in xs["tables"]] for column in [x for xs in tables for x in xs["columns"]]: if 'concept' in column and column["concept"] is not None: tmp.append(column["concept"]) response = tmp - elif type == 'unit': + elif field_type == 'unit': tmp = [] tables = [x for xs in response for x in xs["tables"]] for column in [x for xs in tables for x in xs["columns"]]: if 'unit' in column and column["unit"] is not None: tmp.append(column["unit"]) response = tmp - elif type == 'view': + elif field_type == 'view': response = [x for xs in response for x in xs["views"]] - return dict({'results': response, 'type': type}), 200 + return dict({'results': response, 'type': field_type}), 200 @app.route("/api/search/database/<int:database_id>", methods=["PUT"], endpoint="search_put_database") @@ -436,16 +432,9 @@ def update_database(database_id: int) -> Database | ApiError: logging.error(f"Failed to validate: {e}") return ApiError(status='BAD_REQUEST', message=f'Malformed payload: {e}', code='search.general.missing').model_dump(), 400 - try: - database = OpenSearchClient().update_database(database_id, payload) - logging.info(f"Updated database with id : {database_id}") - return database.model_dump(), 202 - except NotFoundError: - return ApiError(status='NOT_FOUND', message='Failed to find database', - code='search.database.missing').model_dump(), 404 - except TransportError: - return ApiError(status='BAD_REQUEST', message='Failed to update database', - code='search.database.invalid').model_dump(), 400 + database = OpenSearchClient().update_database(database_id, payload) + logging.info(f"Updated database with id : {database_id}") + return database.model_dump(), 202 @app.route("/api/search/database/<int:database_id>", methods=["DELETE"], endpoint="database_delete_database") @@ -455,7 +444,7 @@ def update_database(database_id: int) -> Database | ApiError: def delete_database(database_id: int): try: OpenSearchClient().delete_database(database_id) - return None, 202 + return dumps({}), 202 except NotFoundError: return ApiError(status='NOT_FOUND', message='Failed to find database', code='search.database.missing').model_dump(), 404 diff --git a/dbrepo-search-service/init/.gitignore b/dbrepo-search-service/init/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..588a8e94456726edc68db7182457ab0118ab69bf --- /dev/null +++ b/dbrepo-search-service/init/.gitignore @@ -0,0 +1,5 @@ +# Libraries +./lib/dbrepo-1.4.4* +./lib/dbrepo-1.4.5* +./lib/dbrepo-1.4.6* +./lib/dbrepo-1.4.7rc* \ No newline at end of file diff --git a/dbrepo-search-service/init/Dockerfile b/dbrepo-search-service/init/Dockerfile index ebde913dbd9e013e9591fa4135e919a78fbbbd26..b0704a50470e02dde96effc7cf5e9fc6298cf428 100644 --- a/dbrepo-search-service/init/Dockerfile +++ b/dbrepo-search-service/init/Dockerfile @@ -1,6 +1,7 @@ FROM python:3.11-alpine +LABEL org.opencontainers.image.authors="martin.weise@tuwien.ac.at" -RUN apk add bash curl +RUN apk add --no-cache curl bash jq WORKDIR /home/alpine @@ -16,6 +17,8 @@ USER 1001 WORKDIR /app +COPY --chown=1001 ./clients ./clients +COPY --chown=1001 ./omlib ./omlib COPY --chown=1001 ./app.py ./app.py COPY --chown=1001 ./database.json ./database.json diff --git a/dbrepo-search-service/init/Pipfile b/dbrepo-search-service/init/Pipfile index 517796af748f40cf55f52bac420a000c04c11b23..a6a48b1cfb4d5f8d10e398ca42e636abf6191eff 100644 --- a/dbrepo-search-service/init/Pipfile +++ b/dbrepo-search-service/init/Pipfile @@ -9,7 +9,8 @@ opensearch-py = "~=2.2" python-dotenv = "~=1.0" testcontainers-opensearch = "*" pytest = "*" -dbrepo = {path = "./lib/dbrepo-1.4.4.tar.gz"} +dbrepo = {path = "./lib/dbrepo-1.4.7.tar.gz"} +rdflib = "*" [dev-packages] coverage = "*" diff --git a/dbrepo-search-service/init/Pipfile.lock b/dbrepo-search-service/init/Pipfile.lock index 3053d901cd7867d75f24a1012a84942e21e3ebcd..75bdbc29f92ce91ebd3bca121e904cd2bc05174b 100644 --- a/dbrepo-search-service/init/Pipfile.lock +++ b/dbrepo-search-service/init/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "b12551e0f7592ebabd1eb3ad3efe9e7304c4dcee4fcb065afa88308bff71855d" + "sha256": "17c83557efb9ffbe3c93e34a0df4e794f27b0fb6658915e2c68f4a9a3ef1e09b" }, "pipfile-spec": 6, "requires": { @@ -16,87 +16,110 @@ ] }, "default": { + "aiohappyeyeballs": { + "hashes": [ + "sha256:75cf88a15106a5002a8eb1dab212525c00d1f4c0fa96e551c9fbe6f09a621586", + "sha256:8a7a83727b2756f394ab2895ea0765a0a8c475e3c71e98d43d76f22b4b435572" + ], + "markers": "python_version >= '3.8'", + "version": "==2.4.3" + }, "aiohttp": { "hashes": [ - "sha256:0605cc2c0088fcaae79f01c913a38611ad09ba68ff482402d3410bf59039bfb8", - "sha256:0a158704edf0abcac8ac371fbb54044f3270bdbc93e254a82b6c82be1ef08f3c", - "sha256:0cbf56238f4bbf49dab8c2dc2e6b1b68502b1e88d335bea59b3f5b9f4c001475", - "sha256:1732102949ff6087589408d76cd6dea656b93c896b011ecafff418c9661dc4ed", - "sha256:18f634d540dd099c262e9f887c8bbacc959847cfe5da7a0e2e1cf3f14dbf2daf", - "sha256:239f975589a944eeb1bad26b8b140a59a3a320067fb3cd10b75c3092405a1372", - "sha256:2faa61a904b83142747fc6a6d7ad8fccff898c849123030f8e75d5d967fd4a81", - "sha256:320e8618eda64e19d11bdb3bd04ccc0a816c17eaecb7e4945d01deee2a22f95f", - "sha256:38d80498e2e169bc61418ff36170e0aad0cd268da8b38a17c4cf29d254a8b3f1", - "sha256:3916c8692dbd9d55c523374a3b8213e628424d19116ac4308e434dbf6d95bbdd", - "sha256:393c7aba2b55559ef7ab791c94b44f7482a07bf7640d17b341b79081f5e5cd1a", - "sha256:3b7b30258348082826d274504fbc7c849959f1989d86c29bc355107accec6cfb", - "sha256:3fcb4046d2904378e3aeea1df51f697b0467f2aac55d232c87ba162709478c46", - "sha256:4109adee842b90671f1b689901b948f347325045c15f46b39797ae1bf17019de", - "sha256:4558e5012ee03d2638c681e156461d37b7a113fe13970d438d95d10173d25f78", - "sha256:45731330e754f5811c314901cebdf19dd776a44b31927fa4b4dbecab9e457b0c", - "sha256:4715a9b778f4293b9f8ae7a0a7cef9829f02ff8d6277a39d7f40565c737d3771", - "sha256:471f0ef53ccedec9995287f02caf0c068732f026455f07db3f01a46e49d76bbb", - "sha256:4d3ebb9e1316ec74277d19c5f482f98cc65a73ccd5430540d6d11682cd857430", - "sha256:4ff550491f5492ab5ed3533e76b8567f4b37bd2995e780a1f46bca2024223233", - "sha256:52c27110f3862a1afbcb2af4281fc9fdc40327fa286c4625dfee247c3ba90156", - "sha256:55b39c8684a46e56ef8c8d24faf02de4a2b2ac60d26cee93bc595651ff545de9", - "sha256:5a7ee16aab26e76add4afc45e8f8206c95d1d75540f1039b84a03c3b3800dd59", - "sha256:5ca51eadbd67045396bc92a4345d1790b7301c14d1848feaac1d6a6c9289e888", - "sha256:5d6b3f1fabe465e819aed2c421a6743d8debbde79b6a8600739300630a01bf2c", - "sha256:60cdbd56f4cad9f69c35eaac0fbbdf1f77b0ff9456cebd4902f3dd1cf096464c", - "sha256:6380c039ec52866c06d69b5c7aad5478b24ed11696f0e72f6b807cfb261453da", - "sha256:639d0042b7670222f33b0028de6b4e2fad6451462ce7df2af8aee37dcac55424", - "sha256:66331d00fb28dc90aa606d9a54304af76b335ae204d1836f65797d6fe27f1ca2", - "sha256:67c3119f5ddc7261d47163ed86d760ddf0e625cd6246b4ed852e82159617b5fb", - "sha256:694d828b5c41255e54bc2dddb51a9f5150b4eefa9886e38b52605a05d96566e8", - "sha256:6ae79c1bc12c34082d92bf9422764f799aee4746fd7a392db46b7fd357d4a17a", - "sha256:702e2c7c187c1a498a4e2b03155d52658fdd6fda882d3d7fbb891a5cf108bb10", - "sha256:714d4e5231fed4ba2762ed489b4aec07b2b9953cf4ee31e9871caac895a839c0", - "sha256:7b179eea70833c8dee51ec42f3b4097bd6370892fa93f510f76762105568cf09", - "sha256:7f64cbd44443e80094309875d4f9c71d0401e966d191c3d469cde4642bc2e031", - "sha256:82a6a97d9771cb48ae16979c3a3a9a18b600a8505b1115cfe354dfb2054468b4", - "sha256:84dabd95154f43a2ea80deffec9cb44d2e301e38a0c9d331cc4aa0166fe28ae3", - "sha256:8676e8fd73141ded15ea586de0b7cda1542960a7b9ad89b2b06428e97125d4fa", - "sha256:88e311d98cc0bf45b62fc46c66753a83445f5ab20038bcc1b8a1cc05666f428a", - "sha256:8b4f72fbb66279624bfe83fd5eb6aea0022dad8eec62b71e7bf63ee1caadeafe", - "sha256:8c64a6dc3fe5db7b1b4d2b5cb84c4f677768bdc340611eca673afb7cf416ef5a", - "sha256:8cf142aa6c1a751fcb364158fd710b8a9be874b81889c2bd13aa8893197455e2", - "sha256:8d1964eb7617907c792ca00b341b5ec3e01ae8c280825deadbbd678447b127e1", - "sha256:93e22add827447d2e26d67c9ac0161756007f152fdc5210277d00a85f6c92323", - "sha256:9c69e77370cce2d6df5d12b4e12bdcca60c47ba13d1cbbc8645dd005a20b738b", - "sha256:9dbc053ac75ccc63dc3a3cc547b98c7258ec35a215a92bd9f983e0aac95d3d5b", - "sha256:9e3a1ae66e3d0c17cf65c08968a5ee3180c5a95920ec2731f53343fac9bad106", - "sha256:a6ea1a5b409a85477fd8e5ee6ad8f0e40bf2844c270955e09360418cfd09abac", - "sha256:a81b1143d42b66ffc40a441379387076243ef7b51019204fd3ec36b9f69e77d6", - "sha256:ad7f2919d7dac062f24d6f5fe95d401597fbb015a25771f85e692d043c9d7832", - "sha256:afc52b8d969eff14e069a710057d15ab9ac17cd4b6753042c407dcea0e40bf75", - "sha256:b3df71da99c98534be076196791adca8819761f0bf6e08e07fd7da25127150d6", - "sha256:c088c4d70d21f8ca5c0b8b5403fe84a7bc8e024161febdd4ef04575ef35d474d", - "sha256:c26959ca7b75ff768e2776d8055bf9582a6267e24556bb7f7bd29e677932be72", - "sha256:c413016880e03e69d166efb5a1a95d40f83d5a3a648d16486592c49ffb76d0db", - "sha256:c6021d296318cb6f9414b48e6a439a7f5d1f665464da507e8ff640848ee2a58a", - "sha256:c671dc117c2c21a1ca10c116cfcd6e3e44da7fcde37bf83b2be485ab377b25da", - "sha256:c7a4b7a6cf5b6eb11e109a9755fd4fda7d57395f8c575e166d363b9fc3ec4678", - "sha256:c8a02fbeca6f63cb1f0475c799679057fc9268b77075ab7cf3f1c600e81dd46b", - "sha256:cd2adf5c87ff6d8b277814a28a535b59e20bfea40a101db6b3bdca7e9926bc24", - "sha256:d1469f228cd9ffddd396d9948b8c9cd8022b6d1bf1e40c6f25b0fb90b4f893ed", - "sha256:d153f652a687a8e95ad367a86a61e8d53d528b0530ef382ec5aaf533140ed00f", - "sha256:d5ab8e1f6bee051a4bf6195e38a5c13e5e161cb7bad83d8854524798bd9fcd6e", - "sha256:da00da442a0e31f1c69d26d224e1efd3a1ca5bcbf210978a2ca7426dfcae9f58", - "sha256:da22dab31d7180f8c3ac7c7635f3bcd53808f374f6aa333fe0b0b9e14b01f91a", - "sha256:e0ae53e33ee7476dd3d1132f932eeb39bf6125083820049d06edcdca4381f342", - "sha256:e7a6a8354f1b62e15d48e04350f13e726fa08b62c3d7b8401c0a1314f02e3558", - "sha256:e9a3d838441bebcf5cf442700e3963f58b5c33f015341f9ea86dcd7d503c07e2", - "sha256:edea7d15772ceeb29db4aff55e482d4bcfb6ae160ce144f2682de02f6d693551", - "sha256:f22eb3a6c1080d862befa0a89c380b4dafce29dc6cd56083f630073d102eb595", - "sha256:f26383adb94da5e7fb388d441bf09c61e5e35f455a3217bfd790c6b6bc64b2ee", - "sha256:f3c2890ca8c59ee683fd09adf32321a40fe1cf164e3387799efb2acebf090c11", - "sha256:f64fd07515dad67f24b6ea4a66ae2876c01031de91c93075b8093f07c0a2d93d", - "sha256:fcde4c397f673fdec23e6b05ebf8d4751314fa7c24f93334bf1f1364c1c69ac7", - "sha256:ff84aeb864e0fac81f676be9f4685f0527b660f1efdc40dcede3c251ef1e867f" + "sha256:007ec22fbc573e5eb2fb7dec4198ef8f6bf2fe4ce20020798b2eb5d0abda6138", + "sha256:00819de9e45d42584bed046314c40ea7e9aea95411b38971082cad449392b08c", + "sha256:01948b1d570f83ee7bbf5a60ea2375a89dfb09fd419170e7f5af029510033d24", + "sha256:038f514fe39e235e9fef6717fbf944057bfa24f9b3db9ee551a7ecf584b5b480", + "sha256:03a42ac7895406220124c88911ebee31ba8b2d24c98507f4a8bf826b2937c7f2", + "sha256:05646ebe6b94cc93407b3bf34b9eb26c20722384d068eb7339de802154d61bc5", + "sha256:0631dd7c9f0822cc61c88586ca76d5b5ada26538097d0f1df510b082bad3411a", + "sha256:0b00807e2605f16e1e198f33a53ce3c4523114059b0c09c337209ae55e3823a8", + "sha256:0e1b370d8007c4ae31ee6db7f9a2fe801a42b146cec80a86766e7ad5c4a259cf", + "sha256:15ecd889a709b0080f02721255b3f80bb261c2293d3c748151274dfea93ac871", + "sha256:1b66ccafef7336a1e1f0e389901f60c1d920102315a56df85e49552308fc0486", + "sha256:1bbb122c557a16fafc10354b9d99ebf2f2808a660d78202f10ba9d50786384b9", + "sha256:1eb89d3d29adaf533588f209768a9c02e44e4baf832b08118749c5fad191781d", + "sha256:258c5dd01afc10015866114e210fb7365f0d02d9d059c3c3415382ab633fcbcb", + "sha256:2609e9ab08474702cc67b7702dbb8a80e392c54613ebe80db7e8dbdb79837c68", + "sha256:274cfa632350225ce3fdeb318c23b4a10ec25c0e2c880eff951a3842cf358ac1", + "sha256:28529e08fde6f12eba8677f5a8608500ed33c086f974de68cc65ab218713a59d", + "sha256:2b606353da03edcc71130b52388d25f9a30a126e04caef1fd637e31683033abd", + "sha256:30ca7c3b94708a9d7ae76ff281b2f47d8eaf2579cd05971b5dc681db8caac6e1", + "sha256:333cf6cf8e65f6a1e06e9eb3e643a0c515bb850d470902274239fea02033e9a8", + "sha256:3455522392fb15ff549d92fbf4b73b559d5e43dc522588f7eb3e54c3f38beee7", + "sha256:362f641f9071e5f3ee6f8e7d37d5ed0d95aae656adf4ef578313ee585b585959", + "sha256:3bcd391d083f636c06a68715e69467963d1f9600f85ef556ea82e9ef25f043f7", + "sha256:3dffb610a30d643983aeb185ce134f97f290f8935f0abccdd32c77bed9388b42", + "sha256:3fe407bf93533a6fa82dece0e74dbcaaf5d684e5a51862887f9eaebe6372cd79", + "sha256:413251f6fcf552a33c981c4709a6bba37b12710982fec8e558ae944bfb2abd38", + "sha256:438cd072f75bb6612f2aca29f8bd7cdf6e35e8f160bc312e49fbecab77c99e3a", + "sha256:4470c73c12cd9109db8277287d11f9dd98f77fc54155fc71a7738a83ffcc8ea8", + "sha256:45c3b868724137f713a38376fef8120c166d1eadd50da1855c112fe97954aed8", + "sha256:486f7aabfa292719a2753c016cc3a8f8172965cabb3ea2e7f7436c7f5a22a151", + "sha256:4f05e9727ce409358baa615dbeb9b969db94324a79b5a5cea45d39bdb01d82e6", + "sha256:50aed5155f819873d23520919e16703fc8925e509abbb1a1491b0087d1cd969e", + "sha256:50edbcad60d8f0e3eccc68da67f37268b5144ecc34d59f27a02f9611c1d4eec7", + "sha256:54ca74df1be3c7ca1cf7f4c971c79c2daf48d9aa65dea1a662ae18926f5bc8ce", + "sha256:578a4b875af3e0daaf1ac6fa983d93e0bbfec3ead753b6d6f33d467100cdc67b", + "sha256:597a079284b7ee65ee102bc3a6ea226a37d2b96d0418cc9047490f231dc09fe8", + "sha256:59bb3c54aa420521dc4ce3cc2c3fe2ad82adf7b09403fa1f48ae45c0cbde6628", + "sha256:5c6a5b8c7926ba5d8545c7dd22961a107526562da31a7a32fa2456baf040939f", + "sha256:64f6c17757251e2b8d885d728b6433d9d970573586a78b78ba8929b0f41d045a", + "sha256:679abe5d3858b33c2cf74faec299fda60ea9de62916e8b67e625d65bf069a3b7", + "sha256:741a46d58677d8c733175d7e5aa618d277cd9d880301a380fd296975a9cdd7bc", + "sha256:7789050d9e5d0c309c706953e5e8876e38662d57d45f936902e176d19f1c58ab", + "sha256:77abf6665ae54000b98b3c742bc6ea1d1fb31c394bcabf8b5d2c1ac3ebfe7f3b", + "sha256:79019094f87c9fb44f8d769e41dbb664d6e8fcfd62f665ccce36762deaa0e911", + "sha256:7b06b7843929e41a94ea09eb1ce3927865387e3e23ebe108e0d0d09b08d25be9", + "sha256:7e338c0523d024fad378b376a79faff37fafb3c001872a618cde1d322400a572", + "sha256:7ea7ffc6d6d6f8a11e6f40091a1040995cdff02cfc9ba4c2f30a516cb2633554", + "sha256:8105fd8a890df77b76dd3054cddf01a879fc13e8af576805d667e0fa0224c35d", + "sha256:84afcdea18eda514c25bc68b9af2a2b1adea7c08899175a51fe7c4fb6d551257", + "sha256:9294bbb581f92770e6ed5c19559e1e99255e4ca604a22c5c6397b2f9dd3ee42c", + "sha256:93429602396f3383a797a2a70e5f1de5df8e35535d7806c9f91df06f297e109b", + "sha256:9627cc1a10c8c409b5822a92d57a77f383b554463d1884008e051c32ab1b3742", + "sha256:998f3bd3cfc95e9424a6acd7840cbdd39e45bc09ef87533c006f94ac47296090", + "sha256:9c72109213eb9d3874f7ac8c0c5fa90e072d678e117d9061c06e30c85b4cf0e6", + "sha256:9fc1500fd2a952c5c8e3b29aaf7e3cc6e27e9cfc0a8819b3bce48cc1b849e4cc", + "sha256:a3f00003de6eba42d6e94fabb4125600d6e484846dbf90ea8e48a800430cc142", + "sha256:a45d85cf20b5e0d0aa5a8dca27cce8eddef3292bc29d72dcad1641f4ed50aa16", + "sha256:a7d8d14fe962153fc681f6366bdec33d4356f98a3e3567782aac1b6e0e40109a", + "sha256:a8fa23fe62c436ccf23ff930149c047f060c7126eae3ccea005f0483f27b2e28", + "sha256:aa6658732517ddabe22c9036479eabce6036655ba87a0224c612e1ae6af2087e", + "sha256:aafc8ee9b742ce75044ae9a4d3e60e3d918d15a4c2e08a6c3c3e38fa59b92d94", + "sha256:ab5a5a0c7a7991d90446a198689c0535be89bbd6b410a1f9a66688f0880ec026", + "sha256:acd48d5b80ee80f9432a165c0ac8cbf9253eaddb6113269a5e18699b33958dbb", + "sha256:ad7593bb24b2ab09e65e8a1d385606f0f47c65b5a2ae6c551db67d6653e78c28", + "sha256:baa42524a82f75303f714108fea528ccacf0386af429b69fff141ffef1c534f9", + "sha256:bdfcf6443637c148c4e1a20c48c566aa694fa5e288d34b20fcdc58507882fed3", + "sha256:be7443669ae9c016b71f402e43208e13ddf00912f47f623ee5994e12fc7d4b3f", + "sha256:c02a30b904282777d872266b87b20ed8cc0d1501855e27f831320f471d54d983", + "sha256:c1277cd707c465cd09572a774559a3cc7c7a28802eb3a2a9472588f062097205", + "sha256:c30a0eafc89d28e7f959281b58198a9fa5e99405f716c0289b7892ca345fe45f", + "sha256:c5ce2ce7c997e1971b7184ee37deb6ea9922ef5163c6ee5aa3c274b05f9e12fa", + "sha256:c823bc3971c44ab93e611ab1a46b1eafeae474c0c844aff4b7474287b75fe49c", + "sha256:ce0cdc074d540265bfeb31336e678b4e37316849d13b308607efa527e981f5c2", + "sha256:d1720b4f14c78a3089562b8875b53e36b51c97c51adc53325a69b79b4b48ebcb", + "sha256:d183cf9c797a5291e8301790ed6d053480ed94070637bfaad914dd38b0981f67", + "sha256:d9010c31cd6fa59438da4e58a7f19e4753f7f264300cd152e7f90d4602449762", + "sha256:d9e5e4a85bdb56d224f412d9c98ae4cbd032cc4f3161818f692cd81766eee65a", + "sha256:da1dee8948d2137bb51fbb8a53cce6b1bcc86003c6b42565f008438b806cccd8", + "sha256:df9270660711670e68803107d55c2b5949c2e0f2e4896da176e1ecfc068b974a", + "sha256:e00e3505cd80440f6c98c6d69269dcc2a119f86ad0a9fd70bccc59504bebd68a", + "sha256:e48d5021a84d341bcaf95c8460b152cfbad770d28e5fe14a768988c461b821bc", + "sha256:e7f8b04d83483577fd9200461b057c9f14ced334dcb053090cea1da9c8321a91", + "sha256:edfe3341033a6b53a5c522c802deb2079eee5cbfbb0af032a55064bd65c73a23", + "sha256:ef9c33cc5cbca35808f6c74be11eb7f5f6b14d2311be84a15b594bd3e58b5527", + "sha256:f2d4324a98062be0525d16f768a03e0bbb3b9fe301ceee99611dc9a7953124e6", + "sha256:f3935f82f6f4a3820270842e90456ebad3af15810cf65932bd24da4463bc0a4c", + "sha256:f614ab0c76397661b90b6851a030004dac502e48260ea10f2441abd2207fbcc7", + "sha256:f7db54c7914cc99d901d93a34704833568d86c20925b2762f9fa779f9cd2e70f", + "sha256:fbc6264158392bad9df19537e872d476f7c57adf718944cc1e4495cbabf38e2a", + "sha256:fe2fb38c2ed905a2582948e2de560675e9dfbee94c6d5ccdb1301c6d0a5bf092", + "sha256:ffe595f10566f8276b76dc3a11ae4bb7eba1aac8ddd75811736a15b0d5311414" ], "markers": "python_version >= '3.8'", - "version": "==3.9.5" + "version": "==3.10.10" }, "aiosignal": { "hashes": [ @@ -116,11 +139,11 @@ }, "attrs": { "hashes": [ - "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30", - "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1" + "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346", + "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2" ], "markers": "python_version >= '3.7'", - "version": "==23.2.0" + "version": "==24.2.0" }, "blinker": { "hashes": [ @@ -132,107 +155,122 @@ }, "certifi": { "hashes": [ - "sha256:3cd43f1c6fa7dedc5899d69d3ad0398fd018ad1a17fba83ddaf78aa46c747516", - "sha256:ddc6c8ce995e6987e7faf5e3f1b02b302836a0e5d98ece18392cb1a36c72ad56" + "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8", + "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9" ], "markers": "python_version >= '3.6'", - "version": "==2024.6.2" + "version": "==2024.8.30" }, "charset-normalizer": { "hashes": [ - "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027", - "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087", - "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786", - "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8", - "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09", - "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185", - "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574", - "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e", - "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519", - "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898", - "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269", - "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3", - "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f", - "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6", - "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8", - "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a", - "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73", - "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc", - "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714", - "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2", - "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc", - "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce", - "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d", - "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e", - "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6", - "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269", - "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96", - "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d", - "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a", - "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4", - "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77", - "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d", - "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0", - "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed", - "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068", - "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac", - "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25", - "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8", - "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab", - "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26", - "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2", - "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db", - "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f", - "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5", - "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99", - "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c", - "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d", - "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811", - "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa", - "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a", - "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03", - "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b", - "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04", - "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c", - "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001", - "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458", - "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389", - "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99", - "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985", - "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537", - "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238", - "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f", - "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d", - "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796", - "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a", - "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143", - "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8", - "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c", - "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5", - "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5", - "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711", - "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4", - "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6", - "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c", - "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7", - "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4", - "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b", - "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae", - "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12", - "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c", - "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae", - "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8", - "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887", - "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b", - "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4", - "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f", - "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5", - "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33", - "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519", - "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561" + "sha256:0099d79bdfcf5c1f0c2c72f91516702ebf8b0b8ddd8905f97a8aecf49712c621", + "sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6", + "sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8", + "sha256:0b309d1747110feb25d7ed6b01afdec269c647d382c857ef4663bbe6ad95a912", + "sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c", + "sha256:0de7b687289d3c1b3e8660d0741874abe7888100efe14bd0f9fd7141bcbda92b", + "sha256:1110e22af8ca26b90bd6364fe4c763329b0ebf1ee213ba32b68c73de5752323d", + "sha256:130272c698667a982a5d0e626851ceff662565379baf0ff2cc58067b81d4f11d", + "sha256:136815f06a3ae311fae551c3df1f998a1ebd01ddd424aa5603a4336997629e95", + "sha256:14215b71a762336254351b00ec720a8e85cada43b987da5a042e4ce3e82bd68e", + "sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565", + "sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64", + "sha256:2006769bd1640bdf4d5641c69a3d63b71b81445473cac5ded39740a226fa88ab", + "sha256:20587d20f557fe189b7947d8e7ec5afa110ccf72a3128d61a2a387c3313f46be", + "sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e", + "sha256:27623ba66c183eca01bf9ff833875b459cad267aeeb044477fedac35e19ba907", + "sha256:285e96d9d53422efc0d7a17c60e59f37fbf3dfa942073f666db4ac71e8d726d0", + "sha256:2de62e8801ddfff069cd5c504ce3bc9672b23266597d4e4f50eda28846c322f2", + "sha256:2f6c34da58ea9c1a9515621f4d9ac379871a8f21168ba1b5e09d74250de5ad62", + "sha256:309a7de0a0ff3040acaebb35ec45d18db4b28232f21998851cfa709eeff49d62", + "sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23", + "sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc", + "sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284", + "sha256:40d3ff7fc90b98c637bda91c89d51264a3dcf210cade3a2c6f838c7268d7a4ca", + "sha256:425c5f215d0eecee9a56cdb703203dda90423247421bf0d67125add85d0c4455", + "sha256:43193c5cda5d612f247172016c4bb71251c784d7a4d9314677186a838ad34858", + "sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b", + "sha256:47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594", + "sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc", + "sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db", + "sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b", + "sha256:4ec9dd88a5b71abfc74e9df5ebe7921c35cbb3b641181a531ca65cdb5e8e4dea", + "sha256:4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6", + "sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920", + "sha256:55f56e2ebd4e3bc50442fbc0888c9d8c94e4e06a933804e2af3e89e2f9c1c749", + "sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7", + "sha256:5d447056e2ca60382d460a604b6302d8db69476fd2015c81e7c35417cfabe4cd", + "sha256:5ed2e36c3e9b4f21dd9422f6893dec0abf2cca553af509b10cd630f878d3eb99", + "sha256:5ff2ed8194587faf56555927b3aa10e6fb69d931e33953943bc4f837dfee2242", + "sha256:62f60aebecfc7f4b82e3f639a7d1433a20ec32824db2199a11ad4f5e146ef5ee", + "sha256:63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129", + "sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2", + "sha256:6b493a043635eb376e50eedf7818f2f322eabbaa974e948bd8bdd29eb7ef2a51", + "sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee", + "sha256:6fd30dc99682dc2c603c2b315bded2799019cea829f8bf57dc6b61efde6611c8", + "sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b", + "sha256:7706f5850360ac01d80c89bcef1640683cc12ed87f42579dab6c5d3ed6888613", + "sha256:7782afc9b6b42200f7362858f9e73b1f8316afb276d316336c0ec3bd73312742", + "sha256:79983512b108e4a164b9c8d34de3992f76d48cadc9554c9e60b43f308988aabe", + "sha256:7f683ddc7eedd742e2889d2bfb96d69573fde1d92fcb811979cdb7165bb9c7d3", + "sha256:82357d85de703176b5587dbe6ade8ff67f9f69a41c0733cf2425378b49954de5", + "sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631", + "sha256:86f4e8cca779080f66ff4f191a685ced73d2f72d50216f7112185dc02b90b9b7", + "sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15", + "sha256:8ce7fd6767a1cc5a92a639b391891bf1c268b03ec7e021c7d6d902285259685c", + "sha256:8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea", + "sha256:9289fd5dddcf57bab41d044f1756550f9e7cf0c8e373b8cdf0ce8773dc4bd417", + "sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250", + "sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88", + "sha256:95c3c157765b031331dd4db3c775e58deaee050a3042fcad72cbc4189d7c8dca", + "sha256:980b4f289d1d90ca5efcf07958d3eb38ed9c0b7676bf2831a54d4f66f9c27dfa", + "sha256:9ae4ef0b3f6b41bad6366fb0ea4fc1d7ed051528e113a60fa2a65a9abb5b1d99", + "sha256:9c98230f5042f4945f957d006edccc2af1e03ed5e37ce7c373f00a5a4daa6149", + "sha256:9fa2566ca27d67c86569e8c85297aaf413ffab85a8960500f12ea34ff98e4c41", + "sha256:a14969b8691f7998e74663b77b4c36c0337cb1df552da83d5c9004a93afdb574", + "sha256:a8aacce6e2e1edcb6ac625fb0f8c3a9570ccc7bfba1f63419b3769ccf6a00ed0", + "sha256:a8e538f46104c815be19c975572d74afb53f29650ea2025bbfaef359d2de2f7f", + "sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d", + "sha256:aa693779a8b50cd97570e5a0f343538a8dbd3e496fa5dcb87e29406ad0299654", + "sha256:ab22fbd9765e6954bc0bcff24c25ff71dcbfdb185fcdaca49e81bac68fe724d3", + "sha256:ab2e5bef076f5a235c3774b4f4028a680432cded7cad37bba0fd90d64b187d19", + "sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90", + "sha256:af73657b7a68211996527dbfeffbb0864e043d270580c5aef06dc4b659a4b578", + "sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9", + "sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1", + "sha256:b8831399554b92b72af5932cdbbd4ddc55c55f631bb13ff8fe4e6536a06c5c51", + "sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719", + "sha256:bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236", + "sha256:bd7af3717683bea4c87acd8c0d3d5b44d56120b26fd3f8a692bdd2d5260c620a", + "sha256:bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c", + "sha256:c3e446d253bd88f6377260d07c895816ebf33ffffd56c1c792b13bff9c3e1ade", + "sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944", + "sha256:c94057af19bc953643a33581844649a7fdab902624d2eb739738a30e2b3e60fc", + "sha256:cab5d0b79d987c67f3b9e9c53f54a61360422a5a0bc075f43cab5621d530c3b6", + "sha256:ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6", + "sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27", + "sha256:d5b054862739d276e09928de37c79ddeec42a6e1bfc55863be96a36ba22926f6", + "sha256:dbe03226baf438ac4fda9e2d0715022fd579cb641c4cf639fa40d53b2fe6f3e2", + "sha256:dc15e99b2d8a656f8e666854404f1ba54765871104e50c8e9813af8a7db07f12", + "sha256:dcaf7c1524c0542ee2fc82cc8ec337f7a9f7edee2532421ab200d2b920fc97cf", + "sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114", + "sha256:dd9a8bd8900e65504a305bf8ae6fa9fbc66de94178c420791d0293702fce2df7", + "sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf", + "sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d", + "sha256:e91f541a85298cf35433bf66f3fab2a4a2cff05c127eeca4af174f6d497f0d4b", + "sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed", + "sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03", + "sha256:f09cb5a7bbe1ecae6e87901a2eb23e0256bb524a79ccc53eb0b7629fbe7677c4", + "sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67", + "sha256:f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365", + "sha256:f28f891ccd15c514a0981f3b9db9aa23d62fe1a99997512b0491d2ed323d229a", + "sha256:f3e73a4255342d4eb26ef6df01e3962e73aa29baa3124a8e824c5d3364a65748", + "sha256:f606a1881d2663630ea5b8ce2efe2111740df4b687bd78b34a8131baa007f79b", + "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079", + "sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482" ], "markers": "python_full_version >= '3.7.0'", - "version": "==3.3.2" + "version": "==3.4.0" }, "click": { "hashes": [ @@ -244,10 +282,9 @@ }, "dbrepo": { "hashes": [ - "sha256:d445f1c5a361eae8f3538a395828a297dd999ab36e5bbca0ad1cca9d093b8030" + "sha256:84607677b0826bb9b2fa120aacdf56d16c8d9ae423f435b2bd2c22b1c965a33c" ], - "path": "./lib/dbrepo-1.4.4.tar.gz", - "version": "==1.4.4" + "path": "./lib/dbrepo-1.4.7.tar.gz" }, "docker": { "hashes": [ @@ -269,6 +306,7 @@ "sha256:f69fcd559dc907ed196ab9df0e48471709175e696d6e698dd4dbe940f96ce66b" ], "index": "pypi", + "markers": "python_version >= '3.8'", "version": "==2.3.3" }, "frozenlist": { @@ -356,11 +394,11 @@ }, "idna": { "hashes": [ - "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc", - "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0" + "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", + "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3" ], - "markers": "python_version >= '3.5'", - "version": "==3.7" + "markers": "python_version >= '3.6'", + "version": "==3.10" }, "iniconfig": { "hashes": [ @@ -370,6 +408,13 @@ "markers": "python_version >= '3.7'", "version": "==2.0.0" }, + "isodate": { + "hashes": [ + "sha256:0751eece944162659049d35f4f549ed815792b38793f07cf73381c1c87cbed96", + "sha256:48c5881de7e8b0a0d648cb024c8062dc84e7b840ed81e864c7614fd3c127bde9" + ], + "version": "==0.6.1" + }, "itsdangerous": { "hashes": [ "sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef", @@ -388,224 +433,236 @@ }, "markupsafe": { "hashes": [ - "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf", - "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff", - "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f", - "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3", - "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532", - "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f", - "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617", - "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df", - "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4", - "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906", - "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f", - "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4", - "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8", - "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371", - "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2", - "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465", - "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52", - "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6", - "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169", - "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad", - "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2", - "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0", - "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029", - "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f", - "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a", - "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced", - "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5", - "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c", - "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf", - "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9", - "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb", - "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad", - "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3", - "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1", - "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46", - "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc", - "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a", - "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee", - "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900", - "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5", - "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea", - "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f", - "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5", - "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e", - "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a", - "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f", - "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50", - "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a", - "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b", - "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4", - "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff", - "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2", - "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46", - "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b", - "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf", - "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5", - "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5", - "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab", - "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd", - "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68" + "sha256:0778de17cff1acaeccc3ff30cd99a3fd5c50fc58ad3d6c0e0c4c58092b859396", + "sha256:0f84af7e813784feb4d5e4ff7db633aba6c8ca64a833f61d8e4eade234ef0c38", + "sha256:17b2aea42a7280db02ac644db1d634ad47dcc96faf38ab304fe26ba2680d359a", + "sha256:242d6860f1fd9191aef5fae22b51c5c19767f93fb9ead4d21924e0bcb17619d8", + "sha256:244dbe463d5fb6d7ce161301a03a6fe744dac9072328ba9fc82289238582697b", + "sha256:26627785a54a947f6d7336ce5963569b5d75614619e75193bdb4e06e21d447ad", + "sha256:2a4b34a8d14649315c4bc26bbfa352663eb51d146e35eef231dd739d54a5430a", + "sha256:2ae99f31f47d849758a687102afdd05bd3d3ff7dbab0a8f1587981b58a76152a", + "sha256:312387403cd40699ab91d50735ea7a507b788091c416dd007eac54434aee51da", + "sha256:3341c043c37d78cc5ae6e3e305e988532b072329639007fd408a476642a89fd6", + "sha256:33d1c36b90e570ba7785dacd1faaf091203d9942bc036118fab8110a401eb1a8", + "sha256:3e683ee4f5d0fa2dde4db77ed8dd8a876686e3fc417655c2ece9a90576905344", + "sha256:3ffb4a8e7d46ed96ae48805746755fadd0909fea2306f93d5d8233ba23dda12a", + "sha256:40621d60d0e58aa573b68ac5e2d6b20d44392878e0bfc159012a5787c4e35bc8", + "sha256:40f1e10d51c92859765522cbd79c5c8989f40f0419614bcdc5015e7b6bf97fc5", + "sha256:45d42d132cff577c92bfba536aefcfea7e26efb975bd455db4e6602f5c9f45e7", + "sha256:48488d999ed50ba8d38c581d67e496f955821dc183883550a6fbc7f1aefdc170", + "sha256:4935dd7883f1d50e2ffecca0aa33dc1946a94c8f3fdafb8df5c330e48f71b132", + "sha256:4c2d64fdba74ad16138300815cfdc6ab2f4647e23ced81f59e940d7d4a1469d9", + "sha256:4c8817557d0de9349109acb38b9dd570b03cc5014e8aabf1cbddc6e81005becd", + "sha256:4ffaaac913c3f7345579db4f33b0020db693f302ca5137f106060316761beea9", + "sha256:5a4cb365cb49b750bdb60b846b0c0bc49ed62e59a76635095a179d440540c346", + "sha256:62fada2c942702ef8952754abfc1a9f7658a4d5460fabe95ac7ec2cbe0d02abc", + "sha256:67c519635a4f64e495c50e3107d9b4075aec33634272b5db1cde839e07367589", + "sha256:6a54c43d3ec4cf2a39f4387ad044221c66a376e58c0d0e971d47c475ba79c6b5", + "sha256:7044312a928a66a4c2a22644147bc61a199c1709712069a344a3fb5cfcf16915", + "sha256:730d86af59e0e43ce277bb83970530dd223bf7f2a838e086b50affa6ec5f9295", + "sha256:800100d45176652ded796134277ecb13640c1a537cad3b8b53da45aa96330453", + "sha256:80fcbf3add8790caddfab6764bde258b5d09aefbe9169c183f88a7410f0f6dea", + "sha256:82b5dba6eb1bcc29cc305a18a3c5365d2af06ee71b123216416f7e20d2a84e5b", + "sha256:852dc840f6d7c985603e60b5deaae1d89c56cb038b577f6b5b8c808c97580f1d", + "sha256:8ad4ad1429cd4f315f32ef263c1342166695fad76c100c5d979c45d5570ed58b", + "sha256:8ae369e84466aa70f3154ee23c1451fda10a8ee1b63923ce76667e3077f2b0c4", + "sha256:93e8248d650e7e9d49e8251f883eed60ecbc0e8ffd6349e18550925e31bd029b", + "sha256:973a371a55ce9ed333a3a0f8e0bcfae9e0d637711534bcb11e130af2ab9334e7", + "sha256:9ba25a71ebf05b9bb0e2ae99f8bc08a07ee8e98c612175087112656ca0f5c8bf", + "sha256:a10860e00ded1dd0a65b83e717af28845bb7bd16d8ace40fe5531491de76b79f", + "sha256:a4792d3b3a6dfafefdf8e937f14906a51bd27025a36f4b188728a73382231d91", + "sha256:a7420ceda262dbb4b8d839a4ec63d61c261e4e77677ed7c66c99f4e7cb5030dd", + "sha256:ad91738f14eb8da0ff82f2acd0098b6257621410dcbd4df20aaa5b4233d75a50", + "sha256:b6a387d61fe41cdf7ea95b38e9af11cfb1a63499af2759444b99185c4ab33f5b", + "sha256:b954093679d5750495725ea6f88409946d69cfb25ea7b4c846eef5044194f583", + "sha256:bbde71a705f8e9e4c3e9e33db69341d040c827c7afa6789b14c6e16776074f5a", + "sha256:beeebf760a9c1f4c07ef6a53465e8cfa776ea6a2021eda0d0417ec41043fe984", + "sha256:c91b394f7601438ff79a4b93d16be92f216adb57d813a78be4446fe0f6bc2d8c", + "sha256:c97ff7fedf56d86bae92fa0a646ce1a0ec7509a7578e1ed238731ba13aabcd1c", + "sha256:cb53e2a99df28eee3b5f4fea166020d3ef9116fdc5764bc5117486e6d1211b25", + "sha256:cbf445eb5628981a80f54087f9acdbf84f9b7d862756110d172993b9a5ae81aa", + "sha256:d06b24c686a34c86c8c1fba923181eae6b10565e4d80bdd7bc1c8e2f11247aa4", + "sha256:d98e66a24497637dd31ccab090b34392dddb1f2f811c4b4cd80c230205c074a3", + "sha256:db15ce28e1e127a0013dfb8ac243a8e392db8c61eae113337536edb28bdc1f97", + "sha256:db842712984e91707437461930e6011e60b39136c7331e971952bb30465bc1a1", + "sha256:e24bfe89c6ac4c31792793ad9f861b8f6dc4546ac6dc8f1c9083c7c4f2b335cd", + "sha256:e81c52638315ff4ac1b533d427f50bc0afc746deb949210bc85f05d4f15fd772", + "sha256:e9393357f19954248b00bed7c56f29a25c930593a77630c719653d51e7669c2a", + "sha256:ee3941769bd2522fe39222206f6dd97ae83c442a94c90f2b7a25d847d40f4729", + "sha256:f31ae06f1328595d762c9a2bf29dafd8621c7d3adc130cbb46278079758779ca", + "sha256:f94190df587738280d544971500b9cafc9b950d32efcb1fba9ac10d84e6aa4e6", + "sha256:fa7d686ed9883f3d664d39d5a8e74d3c5f63e603c2e3ff0abcba23eac6542635", + "sha256:fb532dd9900381d2e8f48172ddc5a59db4c445a11b9fab40b3b786da40d3b56b", + "sha256:fe32482b37b4b00c7a52a07211b479653b7fe4f22b2e481b9a9b099d8a430f2f" ], - "markers": "python_version >= '3.7'", - "version": "==2.1.5" + "markers": "python_version >= '3.9'", + "version": "==3.0.1" }, "multidict": { "hashes": [ - "sha256:01265f5e40f5a17f8241d52656ed27192be03bfa8764d88e8220141d1e4b3556", - "sha256:0275e35209c27a3f7951e1ce7aaf93ce0d163b28948444bec61dd7badc6d3f8c", - "sha256:04bde7a7b3de05732a4eb39c94574db1ec99abb56162d6c520ad26f83267de29", - "sha256:04da1bb8c8dbadf2a18a452639771951c662c5ad03aefe4884775454be322c9b", - "sha256:09a892e4a9fb47331da06948690ae38eaa2426de97b4ccbfafbdcbe5c8f37ff8", - "sha256:0d63c74e3d7ab26de115c49bffc92cc77ed23395303d496eae515d4204a625e7", - "sha256:107c0cdefe028703fb5dafe640a409cb146d44a6ae201e55b35a4af8e95457dd", - "sha256:141b43360bfd3bdd75f15ed811850763555a251e38b2405967f8e25fb43f7d40", - "sha256:14c2976aa9038c2629efa2c148022ed5eb4cb939e15ec7aace7ca932f48f9ba6", - "sha256:19fe01cea168585ba0f678cad6f58133db2aa14eccaf22f88e4a6dccadfad8b3", - "sha256:1d147090048129ce3c453f0292e7697d333db95e52616b3793922945804a433c", - "sha256:1d9ea7a7e779d7a3561aade7d596649fbecfa5c08a7674b11b423783217933f9", - "sha256:215ed703caf15f578dca76ee6f6b21b7603791ae090fbf1ef9d865571039ade5", - "sha256:21fd81c4ebdb4f214161be351eb5bcf385426bf023041da2fd9e60681f3cebae", - "sha256:220dd781e3f7af2c2c1053da9fa96d9cf3072ca58f057f4c5adaaa1cab8fc442", - "sha256:228b644ae063c10e7f324ab1ab6b548bdf6f8b47f3ec234fef1093bc2735e5f9", - "sha256:29bfeb0dff5cb5fdab2023a7a9947b3b4af63e9c47cae2a10ad58394b517fddc", - "sha256:2f4848aa3baa109e6ab81fe2006c77ed4d3cd1e0ac2c1fbddb7b1277c168788c", - "sha256:2faa5ae9376faba05f630d7e5e6be05be22913782b927b19d12b8145968a85ea", - "sha256:2ffc42c922dbfddb4a4c3b438eb056828719f07608af27d163191cb3e3aa6cc5", - "sha256:37b15024f864916b4951adb95d3a80c9431299080341ab9544ed148091b53f50", - "sha256:3cc2ad10255f903656017363cd59436f2111443a76f996584d1077e43ee51182", - "sha256:3d25f19500588cbc47dc19081d78131c32637c25804df8414463ec908631e453", - "sha256:403c0911cd5d5791605808b942c88a8155c2592e05332d2bf78f18697a5fa15e", - "sha256:411bf8515f3be9813d06004cac41ccf7d1cd46dfe233705933dd163b60e37600", - "sha256:425bf820055005bfc8aa9a0b99ccb52cc2f4070153e34b701acc98d201693733", - "sha256:435a0984199d81ca178b9ae2c26ec3d49692d20ee29bc4c11a2a8d4514c67eda", - "sha256:4a6a4f196f08c58c59e0b8ef8ec441d12aee4125a7d4f4fef000ccb22f8d7241", - "sha256:4cc0ef8b962ac7a5e62b9e826bd0cd5040e7d401bc45a6835910ed699037a461", - "sha256:51d035609b86722963404f711db441cf7134f1889107fb171a970c9701f92e1e", - "sha256:53689bb4e102200a4fafa9de9c7c3c212ab40a7ab2c8e474491914d2305f187e", - "sha256:55205d03e8a598cfc688c71ca8ea5f66447164efff8869517f175ea632c7cb7b", - "sha256:5c0631926c4f58e9a5ccce555ad7747d9a9f8b10619621f22f9635f069f6233e", - "sha256:5cb241881eefd96b46f89b1a056187ea8e9ba14ab88ba632e68d7a2ecb7aadf7", - "sha256:60d698e8179a42ec85172d12f50b1668254628425a6bd611aba022257cac1386", - "sha256:612d1156111ae11d14afaf3a0669ebf6c170dbb735e510a7438ffe2369a847fd", - "sha256:6214c5a5571802c33f80e6c84713b2c79e024995b9c5897f794b43e714daeec9", - "sha256:6939c95381e003f54cd4c5516740faba40cf5ad3eeff460c3ad1d3e0ea2549bf", - "sha256:69db76c09796b313331bb7048229e3bee7928eb62bab5e071e9f7fcc4879caee", - "sha256:6bf7a982604375a8d49b6cc1b781c1747f243d91b81035a9b43a2126c04766f5", - "sha256:766c8f7511df26d9f11cd3a8be623e59cca73d44643abab3f8c8c07620524e4a", - "sha256:76c0de87358b192de7ea9649beb392f107dcad9ad27276324c24c91774ca5271", - "sha256:76f067f5121dcecf0d63a67f29080b26c43c71a98b10c701b0677e4a065fbd54", - "sha256:7901c05ead4b3fb75113fb1dd33eb1253c6d3ee37ce93305acd9d38e0b5f21a4", - "sha256:79660376075cfd4b2c80f295528aa6beb2058fd289f4c9252f986751a4cd0496", - "sha256:79a6d2ba910adb2cbafc95dad936f8b9386e77c84c35bc0add315b856d7c3abb", - "sha256:7afcdd1fc07befad18ec4523a782cde4e93e0a2bf71239894b8d61ee578c1319", - "sha256:7be7047bd08accdb7487737631d25735c9a04327911de89ff1b26b81745bd4e3", - "sha256:7c6390cf87ff6234643428991b7359b5f59cc15155695deb4eda5c777d2b880f", - "sha256:7df704ca8cf4a073334e0427ae2345323613e4df18cc224f647f251e5e75a527", - "sha256:85f67aed7bb647f93e7520633d8f51d3cbc6ab96957c71272b286b2f30dc70ed", - "sha256:896ebdcf62683551312c30e20614305f53125750803b614e9e6ce74a96232604", - "sha256:92d16a3e275e38293623ebf639c471d3e03bb20b8ebb845237e0d3664914caef", - "sha256:99f60d34c048c5c2fabc766108c103612344c46e35d4ed9ae0673d33c8fb26e8", - "sha256:9fe7b0653ba3d9d65cbe7698cca585bf0f8c83dbbcc710db9c90f478e175f2d5", - "sha256:a3145cb08d8625b2d3fee1b2d596a8766352979c9bffe5d7833e0503d0f0b5e5", - "sha256:aeaf541ddbad8311a87dd695ed9642401131ea39ad7bc8cf3ef3967fd093b626", - "sha256:b55358304d7a73d7bdf5de62494aaf70bd33015831ffd98bc498b433dfe5b10c", - "sha256:b82cc8ace10ab5bd93235dfaab2021c70637005e1ac787031f4d1da63d493c1d", - "sha256:c0868d64af83169e4d4152ec612637a543f7a336e4a307b119e98042e852ad9c", - "sha256:c1c1496e73051918fcd4f58ff2e0f2f3066d1c76a0c6aeffd9b45d53243702cc", - "sha256:c9bf56195c6bbd293340ea82eafd0071cb3d450c703d2c93afb89f93b8386ccc", - "sha256:cbebcd5bcaf1eaf302617c114aa67569dd3f090dd0ce8ba9e35e9985b41ac35b", - "sha256:cd6c8fca38178e12c00418de737aef1261576bd1b6e8c6134d3e729a4e858b38", - "sha256:ceb3b7e6a0135e092de86110c5a74e46bda4bd4fbfeeb3a3bcec79c0f861e450", - "sha256:cf590b134eb70629e350691ecca88eac3e3b8b3c86992042fb82e3cb1830d5e1", - "sha256:d3eb1ceec286eba8220c26f3b0096cf189aea7057b6e7b7a2e60ed36b373b77f", - "sha256:d65f25da8e248202bd47445cec78e0025c0fe7582b23ec69c3b27a640dd7a8e3", - "sha256:d6f6d4f185481c9669b9447bf9d9cf3b95a0e9df9d169bbc17e363b7d5487755", - "sha256:d84a5c3a5f7ce6db1f999fb9438f686bc2e09d38143f2d93d8406ed2dd6b9226", - "sha256:d946b0a9eb8aaa590df1fe082cee553ceab173e6cb5b03239716338629c50c7a", - "sha256:dce1c6912ab9ff5f179eaf6efe7365c1f425ed690b03341911bf4939ef2f3046", - "sha256:de170c7b4fe6859beb8926e84f7d7d6c693dfe8e27372ce3b76f01c46e489fcf", - "sha256:e02021f87a5b6932fa6ce916ca004c4d441509d33bbdbeca70d05dff5e9d2479", - "sha256:e030047e85cbcedbfc073f71836d62dd5dadfbe7531cae27789ff66bc551bd5e", - "sha256:e0e79d91e71b9867c73323a3444724d496c037e578a0e1755ae159ba14f4f3d1", - "sha256:e4428b29611e989719874670fd152b6625500ad6c686d464e99f5aaeeaca175a", - "sha256:e4972624066095e52b569e02b5ca97dbd7a7ddd4294bf4e7247d52635630dd83", - "sha256:e7be68734bd8c9a513f2b0cfd508802d6609da068f40dc57d4e3494cefc92929", - "sha256:e8e94e6912639a02ce173341ff62cc1201232ab86b8a8fcc05572741a5dc7d93", - "sha256:ea1456df2a27c73ce51120fa2f519f1bea2f4a03a917f4a43c8707cf4cbbae1a", - "sha256:ebd8d160f91a764652d3e51ce0d2956b38efe37c9231cd82cfc0bed2e40b581c", - "sha256:eca2e9d0cc5a889850e9bbd68e98314ada174ff6ccd1129500103df7a94a7a44", - "sha256:edd08e6f2f1a390bf137080507e44ccc086353c8e98c657e666c017718561b89", - "sha256:f285e862d2f153a70586579c15c44656f888806ed0e5b56b64489afe4a2dbfba", - "sha256:f2a1dee728b52b33eebff5072817176c172050d44d67befd681609b4746e1c2e", - "sha256:f7e301075edaf50500f0b341543c41194d8df3ae5caf4702f2095f3ca73dd8da", - "sha256:fb616be3538599e797a2017cccca78e354c767165e8858ab5116813146041a24", - "sha256:fce28b3c8a81b6b36dfac9feb1de115bab619b3c13905b419ec71d03a3fc1423", - "sha256:fe5d7785250541f7f5019ab9cba2c71169dc7d74d0f45253f8313f436458a4ef" + "sha256:052e10d2d37810b99cc170b785945421141bf7bb7d2f8799d431e7db229c385f", + "sha256:06809f4f0f7ab7ea2cabf9caca7d79c22c0758b58a71f9d32943ae13c7ace056", + "sha256:071120490b47aa997cca00666923a83f02c7fbb44f71cf7f136df753f7fa8761", + "sha256:0c3f390dc53279cbc8ba976e5f8035eab997829066756d811616b652b00a23a3", + "sha256:0e2b90b43e696f25c62656389d32236e049568b39320e2735d51f08fd362761b", + "sha256:0e5f362e895bc5b9e67fe6e4ded2492d8124bdf817827f33c5b46c2fe3ffaca6", + "sha256:10524ebd769727ac77ef2278390fb0068d83f3acb7773792a5080f2b0abf7748", + "sha256:10a9b09aba0c5b48c53761b7c720aaaf7cf236d5fe394cd399c7ba662d5f9966", + "sha256:16e5f4bf4e603eb1fdd5d8180f1a25f30056f22e55ce51fb3d6ad4ab29f7d96f", + "sha256:188215fc0aafb8e03341995e7c4797860181562380f81ed0a87ff455b70bf1f1", + "sha256:189f652a87e876098bbc67b4da1049afb5f5dfbaa310dd67c594b01c10388db6", + "sha256:1ca0083e80e791cffc6efce7660ad24af66c8d4079d2a750b29001b53ff59ada", + "sha256:1e16bf3e5fc9f44632affb159d30a437bfe286ce9e02754759be5536b169b305", + "sha256:2090f6a85cafc5b2db085124d752757c9d251548cedabe9bd31afe6363e0aff2", + "sha256:20b9b5fbe0b88d0bdef2012ef7dee867f874b72528cf1d08f1d59b0e3850129d", + "sha256:22ae2ebf9b0c69d206c003e2f6a914ea33f0a932d4aa16f236afc049d9958f4a", + "sha256:22f3105d4fb15c8f57ff3959a58fcab6ce36814486500cd7485651230ad4d4ef", + "sha256:23bfd518810af7de1116313ebd9092cb9aa629beb12f6ed631ad53356ed6b86c", + "sha256:27e5fc84ccef8dfaabb09d82b7d179c7cf1a3fbc8a966f8274fcb4ab2eb4cadb", + "sha256:3380252550e372e8511d49481bd836264c009adb826b23fefcc5dd3c69692f60", + "sha256:3702ea6872c5a2a4eeefa6ffd36b042e9773f05b1f37ae3ef7264b1163c2dcf6", + "sha256:37bb93b2178e02b7b618893990941900fd25b6b9ac0fa49931a40aecdf083fe4", + "sha256:3914f5aaa0f36d5d60e8ece6a308ee1c9784cd75ec8151062614657a114c4478", + "sha256:3a37ffb35399029b45c6cc33640a92bef403c9fd388acce75cdc88f58bd19a81", + "sha256:3c8b88a2ccf5493b6c8da9076fb151ba106960a2df90c2633f342f120751a9e7", + "sha256:3e97b5e938051226dc025ec80980c285b053ffb1e25a3db2a3aa3bc046bf7f56", + "sha256:3ec660d19bbc671e3a6443325f07263be452c453ac9e512f5eb935e7d4ac28b3", + "sha256:3efe2c2cb5763f2f1b275ad2bf7a287d3f7ebbef35648a9726e3b69284a4f3d6", + "sha256:483a6aea59cb89904e1ceabd2b47368b5600fb7de78a6e4a2c2987b2d256cf30", + "sha256:4867cafcbc6585e4b678876c489b9273b13e9fff9f6d6d66add5e15d11d926cb", + "sha256:48e171e52d1c4d33888e529b999e5900356b9ae588c2f09a52dcefb158b27506", + "sha256:4a9cb68166a34117d6646c0023c7b759bf197bee5ad4272f420a0141d7eb03a0", + "sha256:4b820514bfc0b98a30e3d85462084779900347e4d49267f747ff54060cc33925", + "sha256:4e18b656c5e844539d506a0a06432274d7bd52a7487e6828c63a63d69185626c", + "sha256:4e9f48f58c2c523d5a06faea47866cd35b32655c46b443f163d08c6d0ddb17d6", + "sha256:50b3a2710631848991d0bf7de077502e8994c804bb805aeb2925a981de58ec2e", + "sha256:55b6d90641869892caa9ca42ff913f7ff1c5ece06474fbd32fb2cf6834726c95", + "sha256:57feec87371dbb3520da6192213c7d6fc892d5589a93db548331954de8248fd2", + "sha256:58130ecf8f7b8112cdb841486404f1282b9c86ccb30d3519faf301b2e5659133", + "sha256:5845c1fd4866bb5dd3125d89b90e57ed3138241540897de748cdf19de8a2fca2", + "sha256:59bfeae4b25ec05b34f1956eaa1cb38032282cd4dfabc5056d0a1ec4d696d3aa", + "sha256:5b48204e8d955c47c55b72779802b219a39acc3ee3d0116d5080c388970b76e3", + "sha256:5c09fcfdccdd0b57867577b719c69e347a436b86cd83747f179dbf0cc0d4c1f3", + "sha256:6180c0ae073bddeb5a97a38c03f30c233e0a4d39cd86166251617d1bbd0af436", + "sha256:682b987361e5fd7a139ed565e30d81fd81e9629acc7d925a205366877d8c8657", + "sha256:6b5d83030255983181005e6cfbac1617ce9746b219bc2aad52201ad121226581", + "sha256:6bb5992037f7a9eff7991ebe4273ea7f51f1c1c511e6a2ce511d0e7bdb754492", + "sha256:73eae06aa53af2ea5270cc066dcaf02cc60d2994bbb2c4ef5764949257d10f43", + "sha256:76f364861c3bfc98cbbcbd402d83454ed9e01a5224bb3a28bf70002a230f73e2", + "sha256:820c661588bd01a0aa62a1283f20d2be4281b086f80dad9e955e690c75fb54a2", + "sha256:82176036e65644a6cc5bd619f65f6f19781e8ec2e5330f51aa9ada7504cc1926", + "sha256:87701f25a2352e5bf7454caa64757642734da9f6b11384c1f9d1a8e699758057", + "sha256:9079dfc6a70abe341f521f78405b8949f96db48da98aeb43f9907f342f627cdc", + "sha256:90f8717cb649eea3504091e640a1b8568faad18bd4b9fcd692853a04475a4b80", + "sha256:957cf8e4b6e123a9eea554fa7ebc85674674b713551de587eb318a2df3e00255", + "sha256:99f826cbf970077383d7de805c0681799491cb939c25450b9b5b3ced03ca99f1", + "sha256:9f636b730f7e8cb19feb87094949ba54ee5357440b9658b2a32a5ce4bce53972", + "sha256:a114d03b938376557927ab23f1e950827c3b893ccb94b62fd95d430fd0e5cf53", + "sha256:a185f876e69897a6f3325c3f19f26a297fa058c5e456bfcff8015e9a27e83ae1", + "sha256:a7a9541cd308eed5e30318430a9c74d2132e9a8cb46b901326272d780bf2d423", + "sha256:aa466da5b15ccea564bdab9c89175c762bc12825f4659c11227f515cee76fa4a", + "sha256:aaed8b0562be4a0876ee3b6946f6869b7bcdb571a5d1496683505944e268b160", + "sha256:ab7c4ceb38d91570a650dba194e1ca87c2b543488fe9309b4212694174fd539c", + "sha256:ac10f4c2b9e770c4e393876e35a7046879d195cd123b4f116d299d442b335bcd", + "sha256:b04772ed465fa3cc947db808fa306d79b43e896beb677a56fb2347ca1a49c1fa", + "sha256:b1c416351ee6271b2f49b56ad7f308072f6f44b37118d69c2cad94f3fa8a40d5", + "sha256:b225d95519a5bf73860323e633a664b0d85ad3d5bede6d30d95b35d4dfe8805b", + "sha256:b2f59caeaf7632cc633b5cf6fc449372b83bbdf0da4ae04d5be36118e46cc0aa", + "sha256:b58c621844d55e71c1b7f7c498ce5aa6985d743a1a59034c57a905b3f153c1ef", + "sha256:bf6bea52ec97e95560af5ae576bdac3aa3aae0b6758c6efa115236d9e07dae44", + "sha256:c08be4f460903e5a9d0f76818db3250f12e9c344e79314d1d570fc69d7f4eae4", + "sha256:c7053d3b0353a8b9de430a4f4b4268ac9a4fb3481af37dfe49825bf45ca24156", + "sha256:c943a53e9186688b45b323602298ab727d8865d8c9ee0b17f8d62d14b56f0753", + "sha256:ce2186a7df133a9c895dea3331ddc5ddad42cdd0d1ea2f0a51e5d161e4762f28", + "sha256:d093be959277cb7dee84b801eb1af388b6ad3ca6a6b6bf1ed7585895789d027d", + "sha256:d094ddec350a2fb899fec68d8353c78233debde9b7d8b4beeafa70825f1c281a", + "sha256:d1a9dd711d0877a1ece3d2e4fea11a8e75741ca21954c919406b44e7cf971304", + "sha256:d569388c381b24671589335a3be6e1d45546c2988c2ebe30fdcada8457a31008", + "sha256:d618649d4e70ac6efcbba75be98b26ef5078faad23592f9b51ca492953012429", + "sha256:d83a047959d38a7ff552ff94be767b7fd79b831ad1cd9920662db05fec24fe72", + "sha256:d8fff389528cad1618fb4b26b95550327495462cd745d879a8c7c2115248e399", + "sha256:da1758c76f50c39a2efd5e9859ce7d776317eb1dd34317c8152ac9251fc574a3", + "sha256:db7457bac39421addd0c8449933ac32d8042aae84a14911a757ae6ca3eef1392", + "sha256:e27bbb6d14416713a8bd7aaa1313c0fc8d44ee48d74497a0ff4c3a1b6ccb5167", + "sha256:e617fb6b0b6953fffd762669610c1c4ffd05632c138d61ac7e14ad187870669c", + "sha256:e9aa71e15d9d9beaad2c6b9319edcdc0a49a43ef5c0a4c8265ca9ee7d6c67774", + "sha256:ec2abea24d98246b94913b76a125e855eb5c434f7c46546046372fe60f666351", + "sha256:f179dee3b863ab1c59580ff60f9d99f632f34ccb38bf67a33ec6b3ecadd0fd76", + "sha256:f4c035da3f544b1882bac24115f3e2e8760f10a0107614fc9839fd232200b875", + "sha256:f67f217af4b1ff66c68a87318012de788dd95fcfeb24cc889011f4e1c7454dfd", + "sha256:f90c822a402cb865e396a504f9fc8173ef34212a342d92e362ca498cad308e28", + "sha256:ff3827aef427c89a25cc96ded1759271a93603aba9fb977a6d264648ebf989db" ], - "markers": "python_version >= '3.7'", - "version": "==6.0.5" + "markers": "python_version >= '3.8'", + "version": "==6.1.0" }, "numpy": { "hashes": [ - "sha256:04494f6ec467ccb5369d1808570ae55f6ed9b5809d7f035059000a37b8d7e86f", - "sha256:0a43f0974d501842866cc83471bdb0116ba0dffdbaac33ec05e6afed5b615238", - "sha256:0e50842b2295ba8414c8c1d9d957083d5dfe9e16828b37de883f51fc53c4016f", - "sha256:0ec84b9ba0654f3b962802edc91424331f423dcf5d5f926676e0150789cb3d95", - "sha256:17067d097ed036636fa79f6a869ac26df7db1ba22039d962422506640314933a", - "sha256:1cde1753efe513705a0c6d28f5884e22bdc30438bf0085c5c486cdaff40cd67a", - "sha256:1e72728e7501a450288fc8e1f9ebc73d90cfd4671ebbd631f3e7857c39bd16f2", - "sha256:2635dbd200c2d6faf2ef9a0d04f0ecc6b13b3cad54f7c67c61155138835515d2", - "sha256:2ce46fd0b8a0c947ae047d222f7136fc4d55538741373107574271bc00e20e8f", - "sha256:34f003cb88b1ba38cb9a9a4a3161c1604973d7f9d5552c38bc2f04f829536609", - "sha256:354f373279768fa5a584bac997de6a6c9bc535c482592d7a813bb0c09be6c76f", - "sha256:38ecb5b0582cd125f67a629072fed6f83562d9dd04d7e03256c9829bdec027ad", - "sha256:3e8e01233d57639b2e30966c63d36fcea099d17c53bf424d77f088b0f4babd86", - "sha256:3f6bed7f840d44c08ebdb73b1825282b801799e325bcbdfa6bc5c370e5aecc65", - "sha256:4554eb96f0fd263041baf16cf0881b3f5dafae7a59b1049acb9540c4d57bc8cb", - "sha256:46e161722e0f619749d1cd892167039015b2c2817296104487cd03ed4a955995", - "sha256:49d9f7d256fbc804391a7f72d4a617302b1afac1112fac19b6c6cec63fe7fe8a", - "sha256:4d2f62e55a4cd9c58c1d9a1c9edaedcd857a73cb6fda875bf79093f9d9086f85", - "sha256:5f64641b42b2429f56ee08b4f427a4d2daf916ec59686061de751a55aafa22e4", - "sha256:63b92c512d9dbcc37f9d81b123dec99fdb318ba38c8059afc78086fe73820275", - "sha256:6d7696c615765091cc5093f76fd1fa069870304beaccfd58b5dcc69e55ef49c1", - "sha256:79e843d186c8fb1b102bef3e2bc35ef81160ffef3194646a7fdd6a73c6b97196", - "sha256:821eedb7165ead9eebdb569986968b541f9908979c2da8a4967ecac4439bae3d", - "sha256:84554fc53daa8f6abf8e8a66e076aff6ece62de68523d9f665f32d2fc50fd66e", - "sha256:8d83bb187fb647643bd56e1ae43f273c7f4dbcdf94550d7938cfc32566756514", - "sha256:903703372d46bce88b6920a0cd86c3ad82dae2dbef157b5fc01b70ea1cfc430f", - "sha256:9416a5c2e92ace094e9f0082c5fd473502c91651fb896bc17690d6fc475128d6", - "sha256:9a1712c015831da583b21c5bfe15e8684137097969c6d22e8316ba66b5baabe4", - "sha256:9c27f0946a3536403efb0e1c28def1ae6730a72cd0d5878db38824855e3afc44", - "sha256:a356364941fb0593bb899a1076b92dfa2029f6f5b8ba88a14fd0984aaf76d0df", - "sha256:a7039a136017eaa92c1848152827e1424701532ca8e8967fe480fe1569dae581", - "sha256:acd3a644e4807e73b4e1867b769fbf1ce8c5d80e7caaef0d90dcdc640dfc9787", - "sha256:ad0c86f3455fbd0de6c31a3056eb822fc939f81b1618f10ff3406971893b62a5", - "sha256:b4c76e3d4c56f145d41b7b6751255feefae92edbc9a61e1758a98204200f30fc", - "sha256:b6f6a8f45d0313db07d6d1d37bd0b112f887e1369758a5419c0370ba915b3871", - "sha256:c5a59996dc61835133b56a32ebe4ef3740ea5bc19b3983ac60cc32be5a665d54", - "sha256:c73aafd1afca80afecb22718f8700b40ac7cab927b8abab3c3e337d70e10e5a2", - "sha256:cee6cc0584f71adefe2c908856ccc98702baf95ff80092e4ca46061538a2ba98", - "sha256:cef04d068f5fb0518a77857953193b6bb94809a806bd0a14983a8f12ada060c9", - "sha256:cf5d1c9e6837f8af9f92b6bd3e86d513cdc11f60fd62185cc49ec7d1aba34864", - "sha256:e61155fae27570692ad1d327e81c6cf27d535a5d7ef97648a17d922224b216de", - "sha256:e7f387600d424f91576af20518334df3d97bc76a300a755f9a8d6e4f5cadd289", - "sha256:ed08d2703b5972ec736451b818c2eb9da80d66c3e84aed1deeb0c345fefe461b", - "sha256:fbd6acc766814ea6443628f4e6751d0da6593dae29c08c0b2606164db026970c", - "sha256:feff59f27338135776f6d4e2ec7aeeac5d5f7a08a83e80869121ef8164b74af9" + "sha256:05b2d4e667895cc55e3ff2b56077e4c8a5604361fc21a042845ea3ad67465aa8", + "sha256:12edb90831ff481f7ef5f6bc6431a9d74dc0e5ff401559a71e5e4611d4f2d466", + "sha256:13311c2db4c5f7609b462bc0f43d3c465424d25c626d95040f073e30f7570e35", + "sha256:13532a088217fa624c99b843eeb54640de23b3414b14aa66d023805eb731066c", + "sha256:13602b3174432a35b16c4cfb5de9a12d229727c3dd47a6ce35111f2ebdf66ff4", + "sha256:1600068c262af1ca9580a527d43dc9d959b0b1d8e56f8a05d830eea39b7c8af6", + "sha256:1b8cde4f11f0a975d1fd59373b32e2f5a562ade7cde4f85b7137f3de8fbb29a0", + "sha256:1c193d0b0238638e6fc5f10f1b074a6993cb13b0b431f64079a509d63d3aa8b7", + "sha256:1ebec5fd716c5a5b3d8dfcc439be82a8407b7b24b230d0ad28a81b61c2f4659a", + "sha256:242b39d00e4944431a3cd2db2f5377e15b5785920421993770cddb89992c3f3a", + "sha256:259ec80d54999cc34cd1eb8ded513cb053c3bf4829152a2e00de2371bd406f5e", + "sha256:2abbf905a0b568706391ec6fa15161fad0fb5d8b68d73c461b3c1bab6064dd62", + "sha256:2cbba4b30bf31ddbe97f1c7205ef976909a93a66bb1583e983adbd155ba72ac2", + "sha256:2ffef621c14ebb0188a8633348504a35c13680d6da93ab5cb86f4e54b7e922b5", + "sha256:30d53720b726ec36a7f88dc873f0eec8447fbc93d93a8f079dfac2629598d6ee", + "sha256:32e16a03138cabe0cb28e1007ee82264296ac0983714094380b408097a418cfe", + "sha256:43cca367bf94a14aca50b89e9bc2061683116cfe864e56740e083392f533ce7a", + "sha256:456e3b11cb79ac9946c822a56346ec80275eaf2950314b249b512896c0d2505e", + "sha256:4d6ec0d4222e8ffdab1744da2560f07856421b367928026fb540e1945f2eeeaf", + "sha256:5006b13a06e0b38d561fab5ccc37581f23c9511879be7693bd33c7cd15ca227c", + "sha256:675c741d4739af2dc20cd6c6a5c4b7355c728167845e3c6b0e824e4e5d36a6c3", + "sha256:6cdb606a7478f9ad91c6283e238544451e3a95f30fb5467fbf715964341a8a86", + "sha256:6d95f286b8244b3649b477ac066c6906fbb2905f8ac19b170e2175d3d799f4df", + "sha256:76322dcdb16fccf2ac56f99048af32259dcc488d9b7e25b51e5eca5147a3fb98", + "sha256:7c1c60328bd964b53f8b835df69ae8198659e2b9302ff9ebb7de4e5a5994db3d", + "sha256:860ec6e63e2c5c2ee5e9121808145c7bf86c96cca9ad396c0bd3e0f2798ccbe2", + "sha256:8e00ea6fc82e8a804433d3e9cedaa1051a1422cb6e443011590c14d2dea59146", + "sha256:9c6c754df29ce6a89ed23afb25550d1c2d5fdb9901d9c67a16e0b16eaf7e2550", + "sha256:a26ae94658d3ba3781d5e103ac07a876b3e9b29db53f68ed7df432fd033358a8", + "sha256:a65acfdb9c6ebb8368490dbafe83c03c7e277b37e6857f0caeadbbc56e12f4fb", + "sha256:a7d80b2e904faa63068ead63107189164ca443b42dd1930299e0d1cb041cec2e", + "sha256:a84498e0d0a1174f2b3ed769b67b656aa5460c92c9554039e11f20a05650f00d", + "sha256:ab4754d432e3ac42d33a269c8567413bdb541689b02d93788af4131018cbf366", + "sha256:ad369ed238b1959dfbade9018a740fb9392c5ac4f9b5173f420bd4f37ba1f7a0", + "sha256:b1d0fcae4f0949f215d4632be684a539859b295e2d0cb14f78ec231915d644db", + "sha256:b42a1a511c81cc78cbc4539675713bbcf9d9c3913386243ceff0e9429ca892fe", + "sha256:bd33f82e95ba7ad632bc57837ee99dba3d7e006536200c4e9124089e1bf42426", + "sha256:bdd407c40483463898b84490770199d5714dcc9dd9b792f6c6caccc523c00952", + "sha256:c6eef7a2dbd0abfb0d9eaf78b73017dbfd0b54051102ff4e6a7b2980d5ac1a03", + "sha256:c82af4b2ddd2ee72d1fc0c6695048d457e00b3582ccde72d8a1c991b808bb20f", + "sha256:d666cb72687559689e9906197e3bec7b736764df6a2e58ee265e360663e9baf7", + "sha256:d7bf0a4f9f15b32b5ba53147369e94296f5fffb783db5aacc1be15b4bf72f43b", + "sha256:d82075752f40c0ddf57e6e02673a17f6cb0f8eb3f587f63ca1eaab5594da5b17", + "sha256:da65fb46d4cbb75cb417cddf6ba5e7582eb7bb0b47db4b99c9fe5787ce5d91f5", + "sha256:e2b49c3c0804e8ecb05d59af8386ec2f74877f7ca8fd9c1e00be2672e4d399b1", + "sha256:e585c8ae871fd38ac50598f4763d73ec5497b0de9a0ab4ef5b69f01c6a046142", + "sha256:e8d3ca0a72dd8846eb6f7dfe8f19088060fcb76931ed592d29128e0219652884", + "sha256:ef444c57d664d35cac4e18c298c47d7b504c66b17c2ea91312e979fcfbdfb08a", + "sha256:f1eb068ead09f4994dec71c24b2844f1e4e4e013b9629f812f292f04bd1510d9", + "sha256:f2ded8d9b6f68cc26f8425eda5d3877b47343e68ca23d0d0846f4d312ecaa445", + "sha256:f751ed0a2f250541e19dfca9f1eafa31a392c71c832b6bb9e113b10d050cb0f1", + "sha256:faa88bc527d0f097abdc2c663cddf37c05a1c2f113716601555249805cf573f1", + "sha256:fc44e3c68ff00fd991b59092a54350e6e4911152682b4782f68070985aa9e648" ], "markers": "python_version == '3.11'", - "version": "==2.0.0" + "version": "==2.1.2" }, "opensearch-py": { "hashes": [ - "sha256:0b7c27e8ed84c03c99558406927b6161f186a72502ca6d0325413d8e5523ba96", - "sha256:b6e78b685dd4e9c016d7a4299cf1de69e299c88322e3f81c716e6e23fe5683c1" + "sha256:5417650eba98a1c7648e502207cebf3a12beab623ffe0ebbf55f9b1b4b6e44e9", + "sha256:67ab76e9373669bc71da417096df59827c08369ac3795d5438c9a8be21cbd759" ], "index": "pypi", - "version": "==2.6.0" + "markers": "python_version >= '3.8' and python_version < '4'", + "version": "==2.7.1" }, "packaging": { "hashes": [ @@ -617,38 +674,51 @@ }, "pandas": { "hashes": [ - "sha256:001910ad31abc7bf06f49dcc903755d2f7f3a9186c0c040b827e522e9cef0863", - "sha256:0ca6377b8fca51815f382bd0b697a0814c8bda55115678cbc94c30aacbb6eff2", - "sha256:0cace394b6ea70c01ca1595f839cf193df35d1575986e484ad35c4aeae7266c1", - "sha256:1cb51fe389360f3b5a4d57dbd2848a5f033350336ca3b340d1c53a1fad33bcad", - "sha256:2925720037f06e89af896c70bca73459d7e6a4be96f9de79e2d440bd499fe0db", - "sha256:3e374f59e440d4ab45ca2fffde54b81ac3834cf5ae2cdfa69c90bc03bde04d76", - "sha256:40ae1dffb3967a52203105a077415a86044a2bea011b5f321c6aa64b379a3f51", - "sha256:43498c0bdb43d55cb162cdc8c06fac328ccb5d2eabe3cadeb3529ae6f0517c32", - "sha256:4abfe0be0d7221be4f12552995e58723c7422c80a659da13ca382697de830c08", - "sha256:58b84b91b0b9f4bafac2a0ac55002280c094dfc6402402332c0913a59654ab2b", - "sha256:640cef9aa381b60e296db324337a554aeeb883ead99dc8f6c18e81a93942f5f4", - "sha256:66b479b0bd07204e37583c191535505410daa8df638fd8e75ae1b383851fe921", - "sha256:696039430f7a562b74fa45f540aca068ea85fa34c244d0deee539cb6d70aa288", - "sha256:6d2123dc9ad6a814bcdea0f099885276b31b24f7edf40f6cdbc0912672e22eee", - "sha256:8635c16bf3d99040fdf3ca3db669a7250ddf49c55dc4aa8fe0ae0fa8d6dcc1f0", - "sha256:873d13d177501a28b2756375d59816c365e42ed8417b41665f346289adc68d24", - "sha256:8e5a0b00e1e56a842f922e7fae8ae4077aee4af0acb5ae3622bd4b4c30aedf99", - "sha256:8e90497254aacacbc4ea6ae5e7a8cd75629d6ad2b30025a4a8b09aa4faf55151", - "sha256:9057e6aa78a584bc93a13f0a9bf7e753a5e9770a30b4d758b8d5f2a62a9433cd", - "sha256:90c6fca2acf139569e74e8781709dccb6fe25940488755716d1d354d6bc58bce", - "sha256:92fd6b027924a7e178ac202cfbe25e53368db90d56872d20ffae94b96c7acc57", - "sha256:9dfde2a0ddef507a631dc9dc4af6a9489d5e2e740e226ad426a05cabfbd7c8ef", - "sha256:9e79019aba43cb4fda9e4d983f8e88ca0373adbb697ae9c6c43093218de28b54", - "sha256:a77e9d1c386196879aa5eb712e77461aaee433e54c68cf253053a73b7e49c33a", - "sha256:c7adfc142dac335d8c1e0dcbd37eb8617eac386596eb9e1a1b77791cf2498238", - "sha256:d187d355ecec3629624fccb01d104da7d7f391db0311145817525281e2804d23", - "sha256:ddf818e4e6c7c6f4f7c8a12709696d193976b591cc7dc50588d3d1a6b5dc8772", - "sha256:e9b79011ff7a0f4b1d6da6a61aa1aa604fb312d6647de5bad20013682d1429ce", - "sha256:eee3a87076c0756de40b05c5e9a6069c035ba43e8dd71c379e68cab2c20f16ad" + "sha256:062309c1b9ea12a50e8ce661145c6aab431b1e99530d3cd60640e255778bd43a", + "sha256:15c0e1e02e93116177d29ff83e8b1619c93ddc9c49083f237d4312337a61165d", + "sha256:1948ddde24197a0f7add2bdc4ca83bf2b1ef84a1bc8ccffd95eda17fd836ecb5", + "sha256:1db71525a1538b30142094edb9adc10be3f3e176748cd7acc2240c2f2e5aa3a4", + "sha256:22a9d949bfc9a502d320aa04e5d02feab689d61da4e7764b62c30b991c42c5f0", + "sha256:29401dbfa9ad77319367d36940cd8a0b3a11aba16063e39632d98b0e931ddf32", + "sha256:31d0ced62d4ea3e231a9f228366919a5ea0b07440d9d4dac345376fd8e1477ea", + "sha256:3508d914817e153ad359d7e069d752cdd736a247c322d932eb89e6bc84217f28", + "sha256:37e0aced3e8f539eccf2e099f65cdb9c8aa85109b0be6e93e2baff94264bdc6f", + "sha256:381175499d3802cde0eabbaf6324cce0c4f5d52ca6f8c377c29ad442f50f6348", + "sha256:38cf8125c40dae9d5acc10fa66af8ea6fdf760b2714ee482ca691fc66e6fcb18", + "sha256:3b71f27954685ee685317063bf13c7709a7ba74fc996b84fc6821c59b0f06468", + "sha256:3fc6873a41186404dad67245896a6e440baacc92f5b716ccd1bc9ed2995ab2c5", + "sha256:4850ba03528b6dd51d6c5d273c46f183f39a9baf3f0143e566b89450965b105e", + "sha256:4f18ba62b61d7e192368b84517265a99b4d7ee8912f8708660fb4a366cc82667", + "sha256:56534ce0746a58afaf7942ba4863e0ef81c9c50d3f0ae93e9497d6a41a057645", + "sha256:59ef3764d0fe818125a5097d2ae867ca3fa64df032331b7e0917cf5d7bf66b13", + "sha256:5dbca4c1acd72e8eeef4753eeca07de9b1db4f398669d5994086f788a5d7cc30", + "sha256:5de54125a92bb4d1c051c0659e6fcb75256bf799a732a87184e5ea503965bce3", + "sha256:61c5ad4043f791b61dd4752191d9f07f0ae412515d59ba8f005832a532f8736d", + "sha256:6374c452ff3ec675a8f46fd9ab25c4ad0ba590b71cf0656f8b6daa5202bca3fb", + "sha256:63cc132e40a2e084cf01adf0775b15ac515ba905d7dcca47e9a251819c575ef3", + "sha256:66108071e1b935240e74525006034333f98bcdb87ea116de573a6a0dccb6c039", + "sha256:6dfcb5ee8d4d50c06a51c2fffa6cff6272098ad6540aed1a76d15fb9318194d8", + "sha256:7c2875855b0ff77b2a64a0365e24455d9990730d6431b9e0ee18ad8acee13dbd", + "sha256:7eee9e7cea6adf3e3d24e304ac6b8300646e2a5d1cd3a3c2abed9101b0846761", + "sha256:800250ecdadb6d9c78eae4990da62743b857b470883fa27f652db8bdde7f6659", + "sha256:86976a1c5b25ae3f8ccae3a5306e443569ee3c3faf444dfd0f41cda24667ad57", + "sha256:8cd6d7cc958a3910f934ea8dbdf17b2364827bb4dafc38ce6eef6bb3d65ff09c", + "sha256:99df71520d25fade9db7c1076ac94eb994f4d2673ef2aa2e86ee039b6746d20c", + "sha256:a5a1595fe639f5988ba6a8e5bc9649af3baf26df3998a0abe56c02609392e0a4", + "sha256:ad5b65698ab28ed8d7f18790a0dc58005c7629f227be9ecc1072aa74c0c1d43a", + "sha256:b1d432e8d08679a40e2a6d8b2f9770a5c21793a6f9f47fdd52c5ce1948a5a8a9", + "sha256:b8661b0238a69d7aafe156b7fa86c44b881387509653fdf857bebc5e4008ad42", + "sha256:ba96630bc17c875161df3818780af30e43be9b166ce51c9a18c1feae342906c2", + "sha256:bc6b93f9b966093cb0fd62ff1a7e4c09e6d546ad7c1de191767baffc57628f39", + "sha256:c124333816c3a9b03fbeef3a9f230ba9a737e9e5bb4060aa2107a86cc0a497fc", + "sha256:cd8d0c3be0515c12fed0bdbae072551c8b54b7192c7b1fda0ba56059a0179698", + "sha256:d9c45366def9a3dd85a6454c0e7908f2b3b8e9c138f5dc38fed7ce720d8453ed", + "sha256:f00d1345d84d8c86a63e476bb4955e46458b304b9575dcf71102b5c705320015", + "sha256:f3a255b2c19987fbbe62a9dfd6cff7ff2aa9ccab3fc75218fd4b7530f01efa24", + "sha256:fffb8ae78d8af97f849404f21411c95062db1496aeb3e56f146f0355c9989319" ], "markers": "python_version >= '3.9'", - "version": "==2.2.2" + "version": "==2.2.3" }, "pika": { "hashes": [ @@ -666,113 +736,236 @@ "markers": "python_version >= '3.8'", "version": "==1.5.0" }, + "propcache": { + "hashes": [ + "sha256:00181262b17e517df2cd85656fcd6b4e70946fe62cd625b9d74ac9977b64d8d9", + "sha256:0e53cb83fdd61cbd67202735e6a6687a7b491c8742dfc39c9e01e80354956763", + "sha256:1235c01ddaa80da8235741e80815ce381c5267f96cc49b1477fdcf8c047ef325", + "sha256:140fbf08ab3588b3468932974a9331aff43c0ab8a2ec2c608b6d7d1756dbb6cb", + "sha256:191db28dc6dcd29d1a3e063c3be0b40688ed76434622c53a284e5427565bbd9b", + "sha256:1e41d67757ff4fbc8ef2af99b338bfb955010444b92929e9e55a6d4dcc3c4f09", + "sha256:1ec43d76b9677637a89d6ab86e1fef70d739217fefa208c65352ecf0282be957", + "sha256:20a617c776f520c3875cf4511e0d1db847a076d720714ae35ffe0df3e440be68", + "sha256:218db2a3c297a3768c11a34812e63b3ac1c3234c3a086def9c0fee50d35add1f", + "sha256:22aa8f2272d81d9317ff5756bb108021a056805ce63dd3630e27d042c8092798", + "sha256:25a1f88b471b3bc911d18b935ecb7115dff3a192b6fef46f0bfaf71ff4f12418", + "sha256:25c8d773a62ce0451b020c7b29a35cfbc05de8b291163a7a0f3b7904f27253e6", + "sha256:2a60ad3e2553a74168d275a0ef35e8c0a965448ffbc3b300ab3a5bb9956c2162", + "sha256:2a66df3d4992bc1d725b9aa803e8c5a66c010c65c741ad901e260ece77f58d2f", + "sha256:2ccc28197af5313706511fab3a8b66dcd6da067a1331372c82ea1cb74285e036", + "sha256:2e900bad2a8456d00a113cad8c13343f3b1f327534e3589acc2219729237a2e8", + "sha256:2ee7606193fb267be4b2e3b32714f2d58cad27217638db98a60f9efb5efeccc2", + "sha256:33ac8f098df0585c0b53009f039dfd913b38c1d2edafed0cedcc0c32a05aa110", + "sha256:3444cdba6628accf384e349014084b1cacd866fbb88433cd9d279d90a54e0b23", + "sha256:363ea8cd3c5cb6679f1c2f5f1f9669587361c062e4899fce56758efa928728f8", + "sha256:375a12d7556d462dc64d70475a9ee5982465fbb3d2b364f16b86ba9135793638", + "sha256:388f3217649d6d59292b722d940d4d2e1e6a7003259eb835724092a1cca0203a", + "sha256:3947483a381259c06921612550867b37d22e1df6d6d7e8361264b6d037595f44", + "sha256:39e104da444a34830751715f45ef9fc537475ba21b7f1f5b0f4d71a3b60d7fe2", + "sha256:3c997f8c44ec9b9b0bcbf2d422cc00a1d9b9c681f56efa6ca149a941e5560da2", + "sha256:3dfafb44f7bb35c0c06eda6b2ab4bfd58f02729e7c4045e179f9a861b07c9850", + "sha256:3ebbcf2a07621f29638799828b8d8668c421bfb94c6cb04269130d8de4fb7136", + "sha256:3f88a4095e913f98988f5b338c1d4d5d07dbb0b6bad19892fd447484e483ba6b", + "sha256:439e76255daa0f8151d3cb325f6dd4a3e93043e6403e6491813bcaaaa8733887", + "sha256:4569158070180c3855e9c0791c56be3ceeb192defa2cdf6a3f39e54319e56b89", + "sha256:466c219deee4536fbc83c08d09115249db301550625c7fef1c5563a584c9bc87", + "sha256:4a9d9b4d0a9b38d1c391bb4ad24aa65f306c6f01b512e10a8a34a2dc5675d348", + "sha256:4c7dde9e533c0a49d802b4f3f218fa9ad0a1ce21f2c2eb80d5216565202acab4", + "sha256:53d1bd3f979ed529f0805dd35ddaca330f80a9a6d90bc0121d2ff398f8ed8861", + "sha256:55346705687dbd7ef0d77883ab4f6fabc48232f587925bdaf95219bae072491e", + "sha256:56295eb1e5f3aecd516d91b00cfd8bf3a13991de5a479df9e27dd569ea23959c", + "sha256:56bb5c98f058a41bb58eead194b4db8c05b088c93d94d5161728515bd52b052b", + "sha256:5a5b3bb545ead161be780ee85a2b54fdf7092815995661947812dde94a40f6fb", + "sha256:5f2564ec89058ee7c7989a7b719115bdfe2a2fb8e7a4543b8d1c0cc4cf6478c1", + "sha256:608cce1da6f2672a56b24a015b42db4ac612ee709f3d29f27a00c943d9e851de", + "sha256:63f13bf09cc3336eb04a837490b8f332e0db41da66995c9fd1ba04552e516354", + "sha256:662dd62358bdeaca0aee5761de8727cfd6861432e3bb828dc2a693aa0471a563", + "sha256:676135dcf3262c9c5081cc8f19ad55c8a64e3f7282a21266d05544450bffc3a5", + "sha256:67aeb72e0f482709991aa91345a831d0b707d16b0257e8ef88a2ad246a7280bf", + "sha256:67b69535c870670c9f9b14a75d28baa32221d06f6b6fa6f77a0a13c5a7b0a5b9", + "sha256:682a7c79a2fbf40f5dbb1eb6bfe2cd865376deeac65acf9beb607505dced9e12", + "sha256:6994984550eaf25dd7fc7bd1b700ff45c894149341725bb4edc67f0ffa94efa4", + "sha256:69d3a98eebae99a420d4b28756c8ce6ea5a29291baf2dc9ff9414b42676f61d5", + "sha256:6e2e54267980349b723cff366d1e29b138b9a60fa376664a157a342689553f71", + "sha256:73e4b40ea0eda421b115248d7e79b59214411109a5bc47d0d48e4c73e3b8fcf9", + "sha256:74acd6e291f885678631b7ebc85d2d4aec458dd849b8c841b57ef04047833bed", + "sha256:7665f04d0c7f26ff8bb534e1c65068409bf4687aa2534faf7104d7182debb336", + "sha256:7735e82e3498c27bcb2d17cb65d62c14f1100b71723b68362872bca7d0913d90", + "sha256:77a86c261679ea5f3896ec060be9dc8e365788248cc1e049632a1be682442063", + "sha256:7cf18abf9764746b9c8704774d8b06714bcb0a63641518a3a89c7f85cc02c2ad", + "sha256:83928404adf8fb3d26793665633ea79b7361efa0287dfbd372a7e74311d51ee6", + "sha256:8e40876731f99b6f3c897b66b803c9e1c07a989b366c6b5b475fafd1f7ba3fb8", + "sha256:8f188cfcc64fb1266f4684206c9de0e80f54622c3f22a910cbd200478aeae61e", + "sha256:91997d9cb4a325b60d4e3f20967f8eb08dfcb32b22554d5ef78e6fd1dda743a2", + "sha256:91ee8fc02ca52e24bcb77b234f22afc03288e1dafbb1f88fe24db308910c4ac7", + "sha256:92fe151145a990c22cbccf9ae15cae8ae9eddabfc949a219c9f667877e40853d", + "sha256:945db8ee295d3af9dbdbb698cce9bbc5c59b5c3fe328bbc4387f59a8a35f998d", + "sha256:9517d5e9e0731957468c29dbfd0f976736a0e55afaea843726e887f36fe017df", + "sha256:952e0d9d07609d9c5be361f33b0d6d650cd2bae393aabb11d9b719364521984b", + "sha256:97a58a28bcf63284e8b4d7b460cbee1edaab24634e82059c7b8c09e65284f178", + "sha256:97e48e8875e6c13909c800fa344cd54cc4b2b0db1d5f911f840458a500fde2c2", + "sha256:9e0f07b42d2a50c7dd2d8675d50f7343d998c64008f1da5fef888396b7f84630", + "sha256:a3dc1a4b165283bd865e8f8cb5f0c64c05001e0718ed06250d8cac9bec115b48", + "sha256:a3ebe9a75be7ab0b7da2464a77bb27febcb4fab46a34f9288f39d74833db7f61", + "sha256:a64e32f8bd94c105cc27f42d3b658902b5bcc947ece3c8fe7bc1b05982f60e89", + "sha256:a6ed8db0a556343d566a5c124ee483ae113acc9a557a807d439bcecc44e7dfbb", + "sha256:ad9c9b99b05f163109466638bd30ada1722abb01bbb85c739c50b6dc11f92dc3", + "sha256:b33d7a286c0dc1a15f5fc864cc48ae92a846df287ceac2dd499926c3801054a6", + "sha256:bc092ba439d91df90aea38168e11f75c655880c12782facf5cf9c00f3d42b562", + "sha256:c436130cc779806bdf5d5fae0d848713105472b8566b75ff70048c47d3961c5b", + "sha256:c5869b8fd70b81835a6f187c5fdbe67917a04d7e52b6e7cc4e5fe39d55c39d58", + "sha256:c5ecca8f9bab618340c8e848d340baf68bcd8ad90a8ecd7a4524a81c1764b3db", + "sha256:cfac69017ef97db2438efb854edf24f5a29fd09a536ff3a992b75990720cdc99", + "sha256:d2f0d0f976985f85dfb5f3d685697ef769faa6b71993b46b295cdbbd6be8cc37", + "sha256:d5bed7f9805cc29c780f3aee05de3262ee7ce1f47083cfe9f77471e9d6777e83", + "sha256:d6a21ef516d36909931a2967621eecb256018aeb11fc48656e3257e73e2e247a", + "sha256:d9b6ddac6408194e934002a69bcaadbc88c10b5f38fb9307779d1c629181815d", + "sha256:db47514ffdbd91ccdc7e6f8407aac4ee94cc871b15b577c1c324236b013ddd04", + "sha256:df81779732feb9d01e5d513fad0122efb3d53bbc75f61b2a4f29a020bc985e70", + "sha256:e4a91d44379f45f5e540971d41e4626dacd7f01004826a18cb048e7da7e96544", + "sha256:e63e3e1e0271f374ed489ff5ee73d4b6e7c60710e1f76af5f0e1a6117cd26394", + "sha256:e70fac33e8b4ac63dfc4c956fd7d85a0b1139adcfc0d964ce288b7c527537fea", + "sha256:ecddc221a077a8132cf7c747d5352a15ed763b674c0448d811f408bf803d9ad7", + "sha256:f45eec587dafd4b2d41ac189c2156461ebd0c1082d2fe7013571598abb8505d1", + "sha256:f52a68c21363c45297aca15561812d542f8fc683c85201df0bebe209e349f793", + "sha256:f571aea50ba5623c308aa146eb650eebf7dbe0fd8c5d946e28343cb3b5aad577", + "sha256:f60f0ac7005b9f5a6091009b09a419ace1610e163fa5deaba5ce3484341840e7", + "sha256:f6475a1b2ecb310c98c28d271a30df74f9dd436ee46d09236a6b750a7599ce57", + "sha256:f6d5749fdd33d90e34c2efb174c7e236829147a2713334d708746e94c4bde40d", + "sha256:f902804113e032e2cdf8c71015651c97af6418363bea8d78dc0911d56c335032", + "sha256:fa1076244f54bb76e65e22cb6910365779d5c3d71d1f18b275f1dfc7b0d71b4d", + "sha256:fc2db02409338bf36590aa985a461b2c96fce91f8e7e0f14c50c5fcc4f229016", + "sha256:ffcad6c564fe6b9b8916c1aefbb37a362deebf9394bd2974e9d84232e3e08504" + ], + "markers": "python_version >= '3.8'", + "version": "==0.2.0" + }, "pydantic": { "hashes": [ - "sha256:0c84efd9548d545f63ac0060c1e4d39bb9b14db8b3c0652338aecc07b5adec52", - "sha256:ee8538d41ccb9c0a9ad3e0e5f07bf15ed8015b481ced539a1759d8cc89ae90d0" + "sha256:d155cef71265d1e9807ed1c32b4c8deec042a44a50a4188b25ac67ecd81a9c0f", + "sha256:f048cec7b26778210e28a0459867920654d48e5e62db0958433636cde4254f12" ], "markers": "python_version >= '3.8'", - "version": "==2.7.4" + "version": "==2.9.2" }, "pydantic-core": { "hashes": [ - "sha256:01dd777215e2aa86dfd664daed5957704b769e726626393438f9c87690ce78c3", - "sha256:0eb2a4f660fcd8e2b1c90ad566db2b98d7f3f4717c64fe0a83e0adb39766d5b8", - "sha256:0fbbdc827fe5e42e4d196c746b890b3d72876bdbf160b0eafe9f0334525119c8", - "sha256:123c3cec203e3f5ac7b000bd82235f1a3eced8665b63d18be751f115588fea30", - "sha256:14601cdb733d741b8958224030e2bfe21a4a881fb3dd6fbb21f071cabd48fa0a", - "sha256:18f469a3d2a2fdafe99296a87e8a4c37748b5080a26b806a707f25a902c040a8", - "sha256:19894b95aacfa98e7cb093cd7881a0c76f55731efad31073db4521e2b6ff5b7d", - "sha256:1b4de2e51bbcb61fdebd0ab86ef28062704f62c82bbf4addc4e37fa4b00b7cbc", - "sha256:1d886dc848e60cb7666f771e406acae54ab279b9f1e4143babc9c2258213daa2", - "sha256:1f4d26ceb5eb9eed4af91bebeae4b06c3fb28966ca3a8fb765208cf6b51102ab", - "sha256:21a5e440dbe315ab9825fcd459b8814bb92b27c974cbc23c3e8baa2b76890077", - "sha256:293afe532740370aba8c060882f7d26cfd00c94cae32fd2e212a3a6e3b7bc15e", - "sha256:2f5966897e5461f818e136b8451d0551a2e77259eb0f73a837027b47dc95dab9", - "sha256:2fd41f6eff4c20778d717af1cc50eca52f5afe7805ee530a4fbd0bae284f16e9", - "sha256:2fdf2156aa3d017fddf8aea5adfba9f777db1d6022d392b682d2a8329e087cef", - "sha256:3c40d4eaad41f78e3bbda31b89edc46a3f3dc6e171bf0ecf097ff7a0ffff7cb1", - "sha256:43d447dd2ae072a0065389092a231283f62d960030ecd27565672bd40746c507", - "sha256:44a688331d4a4e2129140a8118479443bd6f1905231138971372fcde37e43528", - "sha256:44c7486a4228413c317952e9d89598bcdfb06399735e49e0f8df643e1ccd0558", - "sha256:44cd83ab6a51da80fb5adbd9560e26018e2ac7826f9626bc06ca3dc074cd198b", - "sha256:46387e38bd641b3ee5ce247563b60c5ca098da9c56c75c157a05eaa0933ed154", - "sha256:4701b19f7e3a06ea655513f7938de6f108123bf7c86bbebb1196eb9bd35cf724", - "sha256:4748321b5078216070b151d5271ef3e7cc905ab170bbfd27d5c83ee3ec436695", - "sha256:4b06beb3b3f1479d32befd1f3079cc47b34fa2da62457cdf6c963393340b56e9", - "sha256:4d0dcc59664fcb8974b356fe0a18a672d6d7cf9f54746c05f43275fc48636851", - "sha256:4e99bc050fe65c450344421017f98298a97cefc18c53bb2f7b3531eb39bc7805", - "sha256:509daade3b8649f80d4e5ff21aa5673e4ebe58590b25fe42fac5f0f52c6f034a", - "sha256:51991a89639a912c17bef4b45c87bd83593aee0437d8102556af4885811d59f5", - "sha256:53db086f9f6ab2b4061958d9c276d1dbe3690e8dd727d6abf2321d6cce37fa94", - "sha256:564d7922e4b13a16b98772441879fcdcbe82ff50daa622d681dd682175ea918c", - "sha256:574d92eac874f7f4db0ca653514d823a0d22e2354359d0759e3f6a406db5d55d", - "sha256:578e24f761f3b425834f297b9935e1ce2e30f51400964ce4801002435a1b41ef", - "sha256:59ff3e89f4eaf14050c8022011862df275b552caef8082e37b542b066ce1ff26", - "sha256:5f09baa656c904807e832cf9cce799c6460c450c4ad80803517032da0cd062e2", - "sha256:6891a2ae0e8692679c07728819b6e2b822fb30ca7445f67bbf6509b25a96332c", - "sha256:6a750aec7bf431517a9fd78cb93c97b9b0c496090fee84a47a0d23668976b4b0", - "sha256:6f5c4d41b2771c730ea1c34e458e781b18cc668d194958e0112455fff4e402b2", - "sha256:77450e6d20016ec41f43ca4a6c63e9fdde03f0ae3fe90e7c27bdbeaece8b1ed4", - "sha256:81b5efb2f126454586d0f40c4d834010979cb80785173d1586df845a632e4e6d", - "sha256:823be1deb01793da05ecb0484d6c9e20baebb39bd42b5d72636ae9cf8350dbd2", - "sha256:834b5230b5dfc0c1ec37b2fda433b271cbbc0e507560b5d1588e2cc1148cf1ce", - "sha256:847a35c4d58721c5dc3dba599878ebbdfd96784f3fb8bb2c356e123bdcd73f34", - "sha256:86110d7e1907ab36691f80b33eb2da87d780f4739ae773e5fc83fb272f88825f", - "sha256:8951eee36c57cd128f779e641e21eb40bc5073eb28b2d23f33eb0ef14ffb3f5d", - "sha256:8a7164fe2005d03c64fd3b85649891cd4953a8de53107940bf272500ba8a788b", - "sha256:8b8bab4c97248095ae0c4455b5a1cd1cdd96e4e4769306ab19dda135ea4cdb07", - "sha256:90afc12421df2b1b4dcc975f814e21bc1754640d502a2fbcc6d41e77af5ec312", - "sha256:938cb21650855054dc54dfd9120a851c974f95450f00683399006aa6e8abb057", - "sha256:942ba11e7dfb66dc70f9ae66b33452f51ac7bb90676da39a7345e99ffb55402d", - "sha256:972658f4a72d02b8abfa2581d92d59f59897d2e9f7e708fdabe922f9087773af", - "sha256:97736815b9cc893b2b7f663628e63f436018b75f44854c8027040e05230eeddb", - "sha256:98906207f29bc2c459ff64fa007afd10a8c8ac080f7e4d5beff4c97086a3dabd", - "sha256:99457f184ad90235cfe8461c4d70ab7dd2680e28821c29eca00252ba90308c78", - "sha256:a0d829524aaefdebccb869eed855e2d04c21d2d7479b6cada7ace5448416597b", - "sha256:a2fdd81edd64342c85ac7cf2753ccae0b79bf2dfa063785503cb85a7d3593223", - "sha256:a55b5b16c839df1070bc113c1f7f94a0af4433fcfa1b41799ce7606e5c79ce0a", - "sha256:a642295cd0c8df1b86fc3dced1d067874c353a188dc8e0f744626d49e9aa51c4", - "sha256:ab86ce7c8f9bea87b9d12c7f0af71102acbf5ecbc66c17796cff45dae54ef9a5", - "sha256:abc267fa9837245cc28ea6929f19fa335f3dc330a35d2e45509b6566dc18be23", - "sha256:ae1d6df168efb88d7d522664693607b80b4080be6750c913eefb77e34c12c71a", - "sha256:b2ebef0e0b4454320274f5e83a41844c63438fdc874ea40a8b5b4ecb7693f1c4", - "sha256:b48ece5bde2e768197a2d0f6e925f9d7e3e826f0ad2271120f8144a9db18d5c8", - "sha256:b7cdf28938ac6b8b49ae5e92f2735056a7ba99c9b110a474473fd71185c1af5d", - "sha256:bb4462bd43c2460774914b8525f79b00f8f407c945d50881568f294c1d9b4443", - "sha256:bc4ff9805858bd54d1a20efff925ccd89c9d2e7cf4986144b30802bf78091c3e", - "sha256:c1322d7dd74713dcc157a2b7898a564ab091ca6c58302d5c7b4c07296e3fd00f", - "sha256:c67598100338d5d985db1b3d21f3619ef392e185e71b8d52bceacc4a7771ea7e", - "sha256:ca26a1e73c48cfc54c4a76ff78df3727b9d9f4ccc8dbee4ae3f73306a591676d", - "sha256:d323a01da91851a4f17bf592faf46149c9169d68430b3146dcba2bb5e5719abc", - "sha256:dc1803ac5c32ec324c5261c7209e8f8ce88e83254c4e1aebdc8b0a39f9ddb443", - "sha256:e00a3f196329e08e43d99b79b286d60ce46bed10f2280d25a1718399457e06be", - "sha256:e85637bc8fe81ddb73fda9e56bab24560bdddfa98aa64f87aaa4e4b6730c23d2", - "sha256:e858ac0a25074ba4bce653f9b5d0a85b7456eaddadc0ce82d3878c22489fa4ee", - "sha256:eae237477a873ab46e8dd748e515c72c0c804fb380fbe6c85533c7de51f23a8f", - "sha256:ebef0dd9bf9b812bf75bda96743f2a6c5734a02092ae7f721c048d156d5fabae", - "sha256:ec3beeada09ff865c344ff3bc2f427f5e6c26401cc6113d77e372c3fdac73864", - "sha256:f76d0ad001edd426b92233d45c746fd08f467d56100fd8f30e9ace4b005266e4", - "sha256:f85d05aa0918283cf29a30b547b4df2fbb56b45b135f9e35b6807cb28bc47951", - "sha256:f9899c94762343f2cc2fc64c13e7cae4c3cc65cdfc87dd810a31654c9b7358cc" + "sha256:0a7df63886be5e270da67e0966cf4afbae86069501d35c8c1b3b6c168f42cb36", + "sha256:0cb3da3fd1b6a5d0279a01877713dbda118a2a4fc6f0d821a57da2e464793f05", + "sha256:0dbd8dbed2085ed23b5c04afa29d8fd2771674223135dc9bc937f3c09284d071", + "sha256:0dff76e0602ca7d4cdaacc1ac4c005e0ce0dcfe095d5b5259163a80d3a10d327", + "sha256:1278e0d324f6908e872730c9102b0112477a7f7cf88b308e4fc36ce1bdb6d58c", + "sha256:128585782e5bfa515c590ccee4b727fb76925dd04a98864182b22e89a4e6ed36", + "sha256:1498bec4c05c9c787bde9125cfdcc63a41004ff167f495063191b863399b1a29", + "sha256:19442362866a753485ba5e4be408964644dd6a09123d9416c54cd49171f50744", + "sha256:1b84d168f6c48fabd1f2027a3d1bdfe62f92cade1fb273a5d68e621da0e44e6d", + "sha256:1e90d2e3bd2c3863d48525d297cd143fe541be8bbf6f579504b9712cb6b643ec", + "sha256:20152074317d9bed6b7a95ade3b7d6054845d70584216160860425f4fbd5ee9e", + "sha256:216f9b2d7713eb98cb83c80b9c794de1f6b7e3145eef40400c62e86cee5f4e1e", + "sha256:233710f069d251feb12a56da21e14cca67994eab08362207785cf8c598e74577", + "sha256:255a8ef062cbf6674450e668482456abac99a5583bbafb73f9ad469540a3a232", + "sha256:2584f7cf844ac4d970fba483a717dbe10c1c1c96a969bf65d61ffe94df1b2863", + "sha256:2971bb5ffe72cc0f555c13e19b23c85b654dd2a8f7ab493c262071377bfce9f6", + "sha256:29d2c342c4bc01b88402d60189f3df065fb0dda3654744d5a165a5288a657368", + "sha256:2e203fdf807ac7e12ab59ca2bfcabb38c7cf0b33c41efeb00f8e5da1d86af480", + "sha256:33e3d65a85a2a4a0dc3b092b938a4062b1a05f3a9abde65ea93b233bca0e03f2", + "sha256:374a5e5049eda9e0a44c696c7ade3ff355f06b1fe0bb945ea3cac2bc336478a2", + "sha256:37b0fe330e4a58d3c58b24d91d1eb102aeec675a3db4c292ec3928ecd892a9a6", + "sha256:3d5639516376dce1940ea36edf408c554475369f5da2abd45d44621cb616f769", + "sha256:42c6dcb030aefb668a2b7009c85b27f90e51e6a3b4d5c9bc4c57631292015b0d", + "sha256:4a7cd62e831afe623fbb7aabbb4fe583212115b3ef38a9f6b71869ba644624a2", + "sha256:4ba762ed58e8d68657fc1281e9bb72e1c3e79cc5d464be146e260c541ec12d84", + "sha256:4fc714bdbfb534f94034efaa6eadd74e5b93c8fa6315565a222f7b6f42ca1166", + "sha256:4ffa2ebd4c8530079140dd2d7f794a9d9a73cbb8e9d59ffe24c63436efa8f271", + "sha256:5a1504ad17ba4210df3a045132a7baeeba5a200e930f57512ee02909fc5c4cb5", + "sha256:5c364564d17da23db1106787675fc7af45f2f7b58b4173bfdd105564e132e6fb", + "sha256:5e11661ce0fd30a6790e8bcdf263b9ec5988e95e63cf901972107efc49218b13", + "sha256:5f54b118ce5de9ac21c363d9b3caa6c800341e8c47a508787e5868c6b79c9323", + "sha256:5f5ff8d839f4566a474a969508fe1c5e59c31c80d9e140566f9a37bba7b8d556", + "sha256:61817945f2fe7d166e75fbfb28004034b48e44878177fc54d81688e7b85a3665", + "sha256:624e278a7d29b6445e4e813af92af37820fafb6dcc55c012c834f9e26f9aaaef", + "sha256:63e46b3169866bd62849936de036f901a9356e36376079b05efa83caeaa02ceb", + "sha256:6531b7ca5f951d663c339002e91aaebda765ec7d61b7d1e3991051906ddde119", + "sha256:68665f4c17edcceecc112dfed5dbe6f92261fb9d6054b47d01bf6371a6196126", + "sha256:696dd8d674d6ce621ab9d45b205df149399e4bb9aa34102c970b721554828510", + "sha256:6f783e0ec4803c787bcea93e13e9932edab72068f68ecffdf86a99fd5918878b", + "sha256:723314c1d51722ab28bfcd5240d858512ffd3116449c557a1336cbe3919beb87", + "sha256:74b9127ffea03643e998e0c5ad9bd3811d3dac8c676e47db17b0ee7c3c3bf35f", + "sha256:7530e201d10d7d14abce4fb54cfe5b94a0aefc87da539d0346a484ead376c3cc", + "sha256:77733e3892bb0a7fa797826361ce8a9184d25c8dffaec60b7ffe928153680ba8", + "sha256:78ddaaa81421a29574a682b3179d4cf9e6d405a09b99d93ddcf7e5239c742e21", + "sha256:7c9129eb40958b3d4500fa2467e6a83356b3b61bfff1b414c7361d9220f9ae8f", + "sha256:7d32706badfe136888bdea71c0def994644e09fff0bfe47441deaed8e96fdbc6", + "sha256:81965a16b675b35e1d09dd14df53f190f9129c0202356ed44ab2728b1c905658", + "sha256:8394d940e5d400d04cad4f75c0598665cbb81aecefaca82ca85bd28264af7f9b", + "sha256:86d2f57d3e1379a9525c5ab067b27dbb8a0642fb5d454e17a9ac434f9ce523e3", + "sha256:883a91b5dd7d26492ff2f04f40fbb652de40fcc0afe07e8129e8ae779c2110eb", + "sha256:88ad334a15b32a791ea935af224b9de1bf99bcd62fabf745d5f3442199d86d59", + "sha256:9261d3ce84fa1d38ed649c3638feefeae23d32ba9182963e465d58d62203bd24", + "sha256:97df63000f4fea395b2824da80e169731088656d1818a11b95f3b173747b6cd9", + "sha256:98d134c954828488b153d88ba1f34e14259284f256180ce659e8d83e9c05eaa3", + "sha256:996a38a83508c54c78a5f41456b0103c30508fed9abcad0a59b876d7398f25fd", + "sha256:9a5bce9d23aac8f0cf0836ecfc033896aa8443b501c58d0602dbfd5bd5b37753", + "sha256:9a6b5099eeec78827553827f4c6b8615978bb4b6a88e5d9b93eddf8bb6790f55", + "sha256:9d18368b137c6295db49ce7218b1a9ba15c5bc254c96d7c9f9e924a9bc7825ad", + "sha256:a4fa4fc04dff799089689f4fd502ce7d59de529fc2f40a2c8836886c03e0175a", + "sha256:a5c7ba8ffb6d6f8f2ab08743be203654bb1aaa8c9dcb09f82ddd34eadb695605", + "sha256:aea443fffa9fbe3af1a9ba721a87f926fe548d32cab71d188a6ede77d0ff244e", + "sha256:b10bd51f823d891193d4717448fab065733958bdb6a6b351967bd349d48d5c9b", + "sha256:ba1a0996f6c2773bd83e63f18914c1de3c9dd26d55f4ac302a7efe93fb8e7433", + "sha256:bb2802e667b7051a1bebbfe93684841cc9351004e2badbd6411bf357ab8d5ac8", + "sha256:cfdd16ab5e59fc31b5e906d1a3f666571abc367598e3e02c83403acabc092e07", + "sha256:d06b0c8da4f16d1d1e352134427cb194a0a6e19ad5db9161bf32b2113409e728", + "sha256:d0776dea117cf5272382634bd2a5c1b6eb16767c223c6a5317cd3e2a757c61a0", + "sha256:d18ca8148bebe1b0a382a27a8ee60350091a6ddaf475fa05ef50dc35b5df6327", + "sha256:d4488a93b071c04dc20f5cecc3631fc78b9789dd72483ba15d423b5b3689b555", + "sha256:d5f7a395a8cf1621939692dba2a6b6a830efa6b3cee787d82c7de1ad2930de64", + "sha256:d7a80d21d613eec45e3d41eb22f8f94ddc758a6c4720842dc74c0581f54993d6", + "sha256:d97683ddee4723ae8c95d1eddac7c192e8c552da0c73a925a89fa8649bf13eea", + "sha256:dcedcd19a557e182628afa1d553c3895a9f825b936415d0dbd3cd0bbcfd29b4b", + "sha256:de6d1d1b9e5101508cb37ab0d972357cac5235f5c6533d1071964c47139257df", + "sha256:df49e7a0861a8c36d089c1ed57d308623d60416dab2647a4a17fe050ba85de0e", + "sha256:df933278128ea1cd77772673c73954e53a1c95a4fdf41eef97c2b779271bd0bd", + "sha256:e08277a400de01bc72436a0ccd02bdf596631411f592ad985dcee21445bd0068", + "sha256:e38e63e6f3d1cec5a27e0afe90a085af8b6806ee208b33030e65b6516353f1a3", + "sha256:e55541f756f9b3ee346b840103f32779c695a19826a4c442b7954550a0972040", + "sha256:ec4e55f79b1c4ffb2eecd8a0cfba9955a2588497d96851f4c8f99aa4a1d39b12", + "sha256:ed1a53de42fbe34853ba90513cea21673481cd81ed1be739f7f2efb931b24916", + "sha256:ed541d70698978a20eb63d8c5d72f2cc6d7079d9d90f6b50bad07826f1320f5f", + "sha256:f09e2ff1f17c2b51f2bc76d1cc33da96298f0a036a137f5440ab3ec5360b624f", + "sha256:f220b0eea5965dec25480b6333c788fb72ce5f9129e8759ef876a1d805d00801", + "sha256:f3e0da4ebaef65158d4dfd7d3678aad692f7666877df0002b8a522cdf088f231", + "sha256:f455ee30a9d61d3e1a15abd5068827773d6e4dc513e795f380cdd59932c782d5", + "sha256:f5ef8f42bec47f21d07668a043f077d507e5bf4e668d5c6dfe6aaba89de1a5b8", + "sha256:f69a8e0b033b747bb3e36a44e7732f0c99f7edd5cea723d45bc0d6e95377ffee", + "sha256:ff02b6d461a6de369f07ec15e465a88895f3223eb75073ffea56b84d9331f607" ], "markers": "python_version >= '3.8'", - "version": "==2.18.4" + "version": "==2.23.4" + }, + "pyparsing": { + "hashes": [ + "sha256:93d9577b88da0bbea8cc8334ee8b918ed014968fd2ec383e868fb8afb1ccef84", + "sha256:cbf74e27246d595d9a74b186b810f6fbb86726dbf3b9532efb343f6d7294fe9c" + ], + "markers": "python_version >= '3.9'", + "version": "==3.2.0" }, "pytest": { "hashes": [ - "sha256:c434598117762e2bd304e526244f67bf66bbd7b5d6cf22138be51ff661980343", - "sha256:de4bb8104e201939ccdc688b27a89a7be2079b22e2bd2b07f806b6ba71117977" + "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181", + "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2" ], "index": "pypi", - "version": "==8.2.2" + "markers": "python_version >= '3.8'", + "version": "==8.3.3" }, "python-dateutil": { "hashes": [ "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", "version": "==2.9.0.post0" }, "python-dotenv": { @@ -781,14 +974,24 @@ "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a" ], "index": "pypi", + "markers": "python_version >= '3.8'", "version": "==1.0.1" }, "pytz": { "hashes": [ - "sha256:2a29735ea9c18baf14b448846bde5a48030ed267578472d8955cd0e7443a9812", - "sha256:328171f4e3623139da4983451950b28e95ac706e13f3f2630a879749e7a8b319" + "sha256:2aa355083c50a0f93fa581709deac0c9ad65cca8a9e9beac660adcbd493c798a", + "sha256:31c7c1817eb7fae7ca4b8c7ee50c72f93aa2dd863de768e1ef4245d426aa0725" ], - "version": "==2024.1" + "version": "==2024.2" + }, + "rdflib": { + "hashes": [ + "sha256:0438920912a642c866a513de6fe8a0001bd86ef975057d6962c79ce4771687cd", + "sha256:9995eb8569428059b8c1affd26b25eac510d64f5043d9ce8c84e0d0036e995ae" + ], + "index": "pypi", + "markers": "python_full_version >= '3.8.1' and python_full_version < '4.0.0'", + "version": "==7.0.0" }, "requests": { "hashes": [ @@ -803,7 +1006,7 @@ "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", "version": "==1.16.0" }, "testcontainers-core": { @@ -818,15 +1021,16 @@ "sha256:0bdf270b5b7f53915832f7c31dd2bd3ffdc20b534ea6b32231cc7003049bd0e1" ], "index": "pypi", + "markers": "python_version >= '3.7'", "version": "==0.0.1rc1" }, "tinydb": { "hashes": [ - "sha256:30c06d12383d7c332e404ca6a6103fb2b32cbf25712689648c39d9a6bd34bd3d", - "sha256:6dd686a9c5a75dfa9280088fd79a419aefe19cd7f4bd85eba203540ef856d564" + "sha256:f7dfc39b8d7fda7a1ca62a8dbb449ffd340a117c1206b68c50b1a481fb95181d", + "sha256:f97030ee5cbc91eeadd1d7af07ab0e48ceb04aa63d4a983adbaca4cba16e86c3" ], - "markers": "python_version >= '3.7' and python_version < '4.0'", - "version": "==4.8.0" + "markers": "python_version >= '3.8' and python_version < '4.0'", + "version": "==4.8.2" }, "tuspy": { "hashes": [ @@ -841,32 +1045,32 @@ "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8" ], - "markers": "python_version >= '3.8'", + "markers": "python_version < '3.13'", "version": "==4.12.2" }, "tzdata": { "hashes": [ - "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd", - "sha256:9068bc196136463f5245e51efda838afa15aaeca9903f49050dfa2679db4d252" + "sha256:7d85cc416e9382e69095b7bdf4afd9e3880418a2413feec7069d533d6b4e31cc", + "sha256:a48093786cdcde33cad18c2555e8532f34422074448fbc874186f0abd79565cd" ], "markers": "python_version >= '2'", - "version": "==2024.1" + "version": "==2024.2" }, "urllib3": { "hashes": [ - "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472", - "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168" + "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac", + "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9" ], "markers": "python_version >= '3.10'", - "version": "==2.2.2" + "version": "==2.2.3" }, "werkzeug": { "hashes": [ - "sha256:097e5bfda9f0aba8da6b8545146def481d06aa7d3266e7448e2cccf67dd8bd18", - "sha256:fc9645dc43e03e4d630d23143a04a7f947a9a3b5727cd535fdfe155a17cc48c8" + "sha256:02c9eb92b7d6c06f31a782811505d2157837cea66aaede3e217c7c27c039476c", + "sha256:34f2371506b250df4d4f84bfe7b0921e4762525762bbd936614909fe25cd7306" ], "markers": "python_version >= '3.8'", - "version": "==3.0.3" + "version": "==3.0.4" }, "wrapt": { "hashes": [ @@ -946,159 +1150,178 @@ }, "yarl": { "hashes": [ - "sha256:008d3e808d03ef28542372d01057fd09168419cdc8f848efe2804f894ae03e51", - "sha256:03caa9507d3d3c83bca08650678e25364e1843b484f19986a527630ca376ecce", - "sha256:07574b007ee20e5c375a8fe4a0789fad26db905f9813be0f9fef5a68080de559", - "sha256:09efe4615ada057ba2d30df871d2f668af661e971dfeedf0c159927d48bbeff0", - "sha256:0d2454f0aef65ea81037759be5ca9947539667eecebca092733b2eb43c965a81", - "sha256:0e9d124c191d5b881060a9e5060627694c3bdd1fe24c5eecc8d5d7d0eb6faabc", - "sha256:18580f672e44ce1238b82f7fb87d727c4a131f3a9d33a5e0e82b793362bf18b4", - "sha256:1f23e4fe1e8794f74b6027d7cf19dc25f8b63af1483d91d595d4a07eca1fb26c", - "sha256:206a55215e6d05dbc6c98ce598a59e6fbd0c493e2de4ea6cc2f4934d5a18d130", - "sha256:23d32a2594cb5d565d358a92e151315d1b2268bc10f4610d098f96b147370136", - "sha256:26a1dc6285e03f3cc9e839a2da83bcbf31dcb0d004c72d0730e755b33466c30e", - "sha256:29e0f83f37610f173eb7e7b5562dd71467993495e568e708d99e9d1944f561ec", - "sha256:2b134fd795e2322b7684155b7855cc99409d10b2e408056db2b93b51a52accc7", - "sha256:2d47552b6e52c3319fede1b60b3de120fe83bde9b7bddad11a69fb0af7db32f1", - "sha256:357495293086c5b6d34ca9616a43d329317feab7917518bc97a08f9e55648455", - "sha256:35a2b9396879ce32754bd457d31a51ff0a9d426fd9e0e3c33394bf4b9036b099", - "sha256:3777ce5536d17989c91696db1d459574e9a9bd37660ea7ee4d3344579bb6f129", - "sha256:3986b6f41ad22988e53d5778f91855dc0399b043fc8946d4f2e68af22ee9ff10", - "sha256:44d8ffbb9c06e5a7f529f38f53eda23e50d1ed33c6c869e01481d3fafa6b8142", - "sha256:49a180c2e0743d5d6e0b4d1a9e5f633c62eca3f8a86ba5dd3c471060e352ca98", - "sha256:4aa9741085f635934f3a2583e16fcf62ba835719a8b2b28fb2917bb0537c1dfa", - "sha256:4b21516d181cd77ebd06ce160ef8cc2a5e9ad35fb1c5930882baff5ac865eee7", - "sha256:4b3c1ffe10069f655ea2d731808e76e0f452fc6c749bea04781daf18e6039525", - "sha256:4c7d56b293cc071e82532f70adcbd8b61909eec973ae9d2d1f9b233f3d943f2c", - "sha256:4e9035df8d0880b2f1c7f5031f33f69e071dfe72ee9310cfc76f7b605958ceb9", - "sha256:54525ae423d7b7a8ee81ba189f131054defdb122cde31ff17477951464c1691c", - "sha256:549d19c84c55d11687ddbd47eeb348a89df9cb30e1993f1b128f4685cd0ebbf8", - "sha256:54beabb809ffcacbd9d28ac57b0db46e42a6e341a030293fb3185c409e626b8b", - "sha256:566db86717cf8080b99b58b083b773a908ae40f06681e87e589a976faf8246bf", - "sha256:5a2e2433eb9344a163aced6a5f6c9222c0786e5a9e9cac2c89f0b28433f56e23", - "sha256:5aef935237d60a51a62b86249839b51345f47564208c6ee615ed2a40878dccdd", - "sha256:604f31d97fa493083ea21bd9b92c419012531c4e17ea6da0f65cacdcf5d0bd27", - "sha256:63b20738b5aac74e239622d2fe30df4fca4942a86e31bf47a81a0e94c14df94f", - "sha256:686a0c2f85f83463272ddffd4deb5e591c98aac1897d65e92319f729c320eece", - "sha256:6a962e04b8f91f8c4e5917e518d17958e3bdee71fd1d8b88cdce74dd0ebbf434", - "sha256:6ad6d10ed9b67a382b45f29ea028f92d25bc0bc1daf6c5b801b90b5aa70fb9ec", - "sha256:6f5cb257bc2ec58f437da2b37a8cd48f666db96d47b8a3115c29f316313654ff", - "sha256:6fe79f998a4052d79e1c30eeb7d6c1c1056ad33300f682465e1b4e9b5a188b78", - "sha256:7855426dfbddac81896b6e533ebefc0af2f132d4a47340cee6d22cac7190022d", - "sha256:7d5aaac37d19b2904bb9dfe12cdb08c8443e7ba7d2852894ad448d4b8f442863", - "sha256:801e9264d19643548651b9db361ce3287176671fb0117f96b5ac0ee1c3530d53", - "sha256:81eb57278deb6098a5b62e88ad8281b2ba09f2f1147c4767522353eaa6260b31", - "sha256:824d6c50492add5da9374875ce72db7a0733b29c2394890aef23d533106e2b15", - "sha256:8397a3817d7dcdd14bb266283cd1d6fc7264a48c186b986f32e86d86d35fbac5", - "sha256:848cd2a1df56ddbffeb375535fb62c9d1645dde33ca4d51341378b3f5954429b", - "sha256:84fc30f71689d7fc9168b92788abc977dc8cefa806909565fc2951d02f6b7d57", - "sha256:8619d6915b3b0b34420cf9b2bb6d81ef59d984cb0fde7544e9ece32b4b3043c3", - "sha256:8a854227cf581330ffa2c4824d96e52ee621dd571078a252c25e3a3b3d94a1b1", - "sha256:8be9e837ea9113676e5754b43b940b50cce76d9ed7d2461df1af39a8ee674d9f", - "sha256:928cecb0ef9d5a7946eb6ff58417ad2fe9375762382f1bf5c55e61645f2c43ad", - "sha256:957b4774373cf6f709359e5c8c4a0af9f6d7875db657adb0feaf8d6cb3c3964c", - "sha256:992f18e0ea248ee03b5a6e8b3b4738850ae7dbb172cc41c966462801cbf62cf7", - "sha256:9fc5fc1eeb029757349ad26bbc5880557389a03fa6ada41703db5e068881e5f2", - "sha256:a00862fb23195b6b8322f7d781b0dc1d82cb3bcac346d1e38689370cc1cc398b", - "sha256:a3a6ed1d525bfb91b3fc9b690c5a21bb52de28c018530ad85093cc488bee2dd2", - "sha256:a6327976c7c2f4ee6816eff196e25385ccc02cb81427952414a64811037bbc8b", - "sha256:a7409f968456111140c1c95301cadf071bd30a81cbd7ab829169fb9e3d72eae9", - "sha256:a825ec844298c791fd28ed14ed1bffc56a98d15b8c58a20e0e08c1f5f2bea1be", - "sha256:a8c1df72eb746f4136fe9a2e72b0c9dc1da1cbd23b5372f94b5820ff8ae30e0e", - "sha256:a9bd00dc3bc395a662900f33f74feb3e757429e545d831eef5bb280252631984", - "sha256:aa102d6d280a5455ad6a0f9e6d769989638718e938a6a0a2ff3f4a7ff8c62cc4", - "sha256:aaaea1e536f98754a6e5c56091baa1b6ce2f2700cc4a00b0d49eca8dea471074", - "sha256:ad4d7a90a92e528aadf4965d685c17dacff3df282db1121136c382dc0b6014d2", - "sha256:b8477c1ee4bd47c57d49621a062121c3023609f7a13b8a46953eb6c9716ca392", - "sha256:ba6f52cbc7809cd8d74604cce9c14868306ae4aa0282016b641c661f981a6e91", - "sha256:bac8d525a8dbc2a1507ec731d2867025d11ceadcb4dd421423a5d42c56818541", - "sha256:bef596fdaa8f26e3d66af846bbe77057237cb6e8efff8cd7cc8dff9a62278bbf", - "sha256:c0ec0ed476f77db9fb29bca17f0a8fcc7bc97ad4c6c1d8959c507decb22e8572", - "sha256:c38c9ddb6103ceae4e4498f9c08fac9b590c5c71b0370f98714768e22ac6fa66", - "sha256:c7224cab95645c7ab53791022ae77a4509472613e839dab722a72abe5a684575", - "sha256:c74018551e31269d56fab81a728f683667e7c28c04e807ba08f8c9e3bba32f14", - "sha256:ca06675212f94e7a610e85ca36948bb8fc023e458dd6c63ef71abfd482481aa5", - "sha256:d1d2532b340b692880261c15aee4dc94dd22ca5d61b9db9a8a361953d36410b1", - "sha256:d25039a474c4c72a5ad4b52495056f843a7ff07b632c1b92ea9043a3d9950f6e", - "sha256:d5ff2c858f5f6a42c2a8e751100f237c5e869cbde669a724f2062d4c4ef93551", - "sha256:d7d7f7de27b8944f1fee2c26a88b4dabc2409d2fea7a9ed3df79b67277644e17", - "sha256:d7eeb6d22331e2fd42fce928a81c697c9ee2d51400bd1a28803965883e13cead", - "sha256:d8a1c6c0be645c745a081c192e747c5de06e944a0d21245f4cf7c05e457c36e0", - "sha256:d8b889777de69897406c9fb0b76cdf2fd0f31267861ae7501d93003d55f54fbe", - "sha256:d9e09c9d74f4566e905a0b8fa668c58109f7624db96a2171f21747abc7524234", - "sha256:db8e58b9d79200c76956cefd14d5c90af54416ff5353c5bfd7cbe58818e26ef0", - "sha256:ddb2a5c08a4eaaba605340fdee8fc08e406c56617566d9643ad8bf6852778fc7", - "sha256:e0381b4ce23ff92f8170080c97678040fc5b08da85e9e292292aba67fdac6c34", - "sha256:e23a6d84d9d1738dbc6e38167776107e63307dfc8ad108e580548d1f2c587f42", - "sha256:e516dc8baf7b380e6c1c26792610230f37147bb754d6426462ab115a02944385", - "sha256:ea65804b5dc88dacd4a40279af0cdadcfe74b3e5b4c897aa0d81cf86927fee78", - "sha256:ec61d826d80fc293ed46c9dd26995921e3a82146feacd952ef0757236fc137be", - "sha256:ee04010f26d5102399bd17f8df8bc38dc7ccd7701dc77f4a68c5b8d733406958", - "sha256:f3bc6af6e2b8f92eced34ef6a96ffb248e863af20ef4fde9448cc8c9b858b749", - "sha256:f7d6b36dd2e029b6bcb8a13cf19664c7b8e19ab3a58e0fefbb5b8461447ed5ec" + "sha256:0545de8c688fbbf3088f9e8b801157923be4bf8e7b03e97c2ecd4dfa39e48e0e", + "sha256:076b1ed2ac819933895b1a000904f62d615fe4533a5cf3e052ff9a1da560575c", + "sha256:0afad2cd484908f472c8fe2e8ef499facee54a0a6978be0e0cff67b1254fd747", + "sha256:0ccaa1bc98751fbfcf53dc8dfdb90d96e98838010fc254180dd6707a6e8bb179", + "sha256:0d3105efab7c5c091609abacad33afff33bdff0035bece164c98bcf5a85ef90a", + "sha256:0e1af74a9529a1137c67c887ed9cde62cff53aa4d84a3adbec329f9ec47a3936", + "sha256:136f9db0f53c0206db38b8cd0c985c78ded5fd596c9a86ce5c0b92afb91c3a19", + "sha256:156ececdf636143f508770bf8a3a0498de64da5abd890c7dbb42ca9e3b6c05b8", + "sha256:15c87339490100c63472a76d87fe7097a0835c705eb5ae79fd96e343473629ed", + "sha256:1695497bb2a02a6de60064c9f077a4ae9c25c73624e0d43e3aa9d16d983073c2", + "sha256:173563f3696124372831007e3d4b9821746964a95968628f7075d9231ac6bb33", + "sha256:173866d9f7409c0fb514cf6e78952e65816600cb888c68b37b41147349fe0057", + "sha256:23ec1d3c31882b2a8a69c801ef58ebf7bae2553211ebbddf04235be275a38548", + "sha256:243fbbbf003754fe41b5bdf10ce1e7f80bcc70732b5b54222c124d6b4c2ab31c", + "sha256:28c6cf1d92edf936ceedc7afa61b07e9d78a27b15244aa46bbcd534c7458ee1b", + "sha256:2aa738e0282be54eede1e3f36b81f1e46aee7ec7602aa563e81e0e8d7b67963f", + "sha256:2cf441c4b6e538ba0d2591574f95d3fdd33f1efafa864faa077d9636ecc0c4e9", + "sha256:30c3ff305f6e06650a761c4393666f77384f1cc6c5c0251965d6bfa5fbc88f7f", + "sha256:31561a5b4d8dbef1559b3600b045607cf804bae040f64b5f5bca77da38084a8a", + "sha256:32b66be100ac5739065496c74c4b7f3015cef792c3174982809274d7e51b3e04", + "sha256:3433da95b51a75692dcf6cc8117a31410447c75a9a8187888f02ad45c0a86c50", + "sha256:34a2d76a1984cac04ff8b1bfc939ec9dc0914821264d4a9c8fd0ed6aa8d4cfd2", + "sha256:353665775be69bbfc6d54c8d134bfc533e332149faeddd631b0bc79df0897f46", + "sha256:38d0124fa992dbacd0c48b1b755d3ee0a9f924f427f95b0ef376556a24debf01", + "sha256:3c56ec1eacd0a5d35b8a29f468659c47f4fe61b2cab948ca756c39b7617f0aa5", + "sha256:3db817b4e95eb05c362e3b45dafe7144b18603e1211f4a5b36eb9522ecc62bcf", + "sha256:3e52474256a7db9dcf3c5f4ca0b300fdea6c21cca0148c8891d03a025649d935", + "sha256:416f2e3beaeae81e2f7a45dc711258be5bdc79c940a9a270b266c0bec038fb84", + "sha256:435aca062444a7f0c884861d2e3ea79883bd1cd19d0a381928b69ae1b85bc51d", + "sha256:4388c72174868884f76affcdd3656544c426407e0043c89b684d22fb265e04a5", + "sha256:43ebdcc120e2ca679dba01a779333a8ea76b50547b55e812b8b92818d604662c", + "sha256:458c0c65802d816a6b955cf3603186de79e8fdb46d4f19abaec4ef0a906f50a7", + "sha256:533a28754e7f7439f217550a497bb026c54072dbe16402b183fdbca2431935a9", + "sha256:553dad9af802a9ad1a6525e7528152a015b85fb8dbf764ebfc755c695f488367", + "sha256:5838f2b79dc8f96fdc44077c9e4e2e33d7089b10788464609df788eb97d03aad", + "sha256:5b48388ded01f6f2429a8c55012bdbd1c2a0c3735b3e73e221649e524c34a58d", + "sha256:5bc0df728e4def5e15a754521e8882ba5a5121bd6b5a3a0ff7efda5d6558ab3d", + "sha256:63eab904f8630aed5a68f2d0aeab565dcfc595dc1bf0b91b71d9ddd43dea3aea", + "sha256:66f629632220a4e7858b58e4857927dd01a850a4cef2fb4044c8662787165cf7", + "sha256:670eb11325ed3a6209339974b276811867defe52f4188fe18dc49855774fa9cf", + "sha256:69d5856d526802cbda768d3e6246cd0d77450fa2a4bc2ea0ea14f0d972c2894b", + "sha256:6e840553c9c494a35e449a987ca2c4f8372668ee954a03a9a9685075228e5036", + "sha256:711bdfae4e699a6d4f371137cbe9e740dc958530cb920eb6f43ff9551e17cfbc", + "sha256:74abb8709ea54cc483c4fb57fb17bb66f8e0f04438cff6ded322074dbd17c7ec", + "sha256:75119badf45f7183e10e348edff5a76a94dc19ba9287d94001ff05e81475967b", + "sha256:766dcc00b943c089349d4060b935c76281f6be225e39994c2ccec3a2a36ad627", + "sha256:78e6fdc976ec966b99e4daa3812fac0274cc28cd2b24b0d92462e2e5ef90d368", + "sha256:81dadafb3aa124f86dc267a2168f71bbd2bfb163663661ab0038f6e4b8edb810", + "sha256:82d5161e8cb8f36ec778fd7ac4d740415d84030f5b9ef8fe4da54784a1f46c94", + "sha256:833547179c31f9bec39b49601d282d6f0ea1633620701288934c5f66d88c3e50", + "sha256:856b7f1a7b98a8c31823285786bd566cf06226ac4f38b3ef462f593c608a9bd6", + "sha256:8657d3f37f781d987037f9cc20bbc8b40425fa14380c87da0cb8dfce7c92d0fb", + "sha256:93bed8a8084544c6efe8856c362af08a23e959340c87a95687fdbe9c9f280c8b", + "sha256:954dde77c404084c2544e572f342aef384240b3e434e06cecc71597e95fd1ce7", + "sha256:98f68df80ec6ca3015186b2677c208c096d646ef37bbf8b49764ab4a38183931", + "sha256:99e12d2bf587b44deb74e0d6170fec37adb489964dbca656ec41a7cd8f2ff178", + "sha256:9a13a07532e8e1c4a5a3afff0ca4553da23409fad65def1b71186fb867eeae8d", + "sha256:9c1e3ff4b89cdd2e1a24c214f141e848b9e0451f08d7d4963cb4108d4d798f1f", + "sha256:9ce2e0f6123a60bd1a7f5ae3b2c49b240c12c132847f17aa990b841a417598a2", + "sha256:9fcda20b2de7042cc35cf911702fa3d8311bd40055a14446c1e62403684afdc5", + "sha256:a32d58f4b521bb98b2c0aa9da407f8bd57ca81f34362bcb090e4a79e9924fefc", + "sha256:a39c36f4218a5bb668b4f06874d676d35a035ee668e6e7e3538835c703634b84", + "sha256:a5cafb02cf097a82d74403f7e0b6b9df3ffbfe8edf9415ea816314711764a27b", + "sha256:a7cf963a357c5f00cb55b1955df8bbe68d2f2f65de065160a1c26b85a1e44172", + "sha256:a880372e2e5dbb9258a4e8ff43f13888039abb9dd6d515f28611c54361bc5644", + "sha256:ace4cad790f3bf872c082366c9edd7f8f8f77afe3992b134cfc810332206884f", + "sha256:af8ff8d7dc07ce873f643de6dfbcd45dc3db2c87462e5c387267197f59e6d776", + "sha256:b47a6000a7e833ebfe5886b56a31cb2ff12120b1efd4578a6fcc38df16cc77bd", + "sha256:b71862a652f50babab4a43a487f157d26b464b1dedbcc0afda02fd64f3809d04", + "sha256:b7f227ca6db5a9fda0a2b935a2ea34a7267589ffc63c8045f0e4edb8d8dcf956", + "sha256:bc8936d06cd53fddd4892677d65e98af514c8d78c79864f418bbf78a4a2edde4", + "sha256:bed1b5dbf90bad3bfc19439258c97873eab453c71d8b6869c136346acfe497e7", + "sha256:c45817e3e6972109d1a2c65091504a537e257bc3c885b4e78a95baa96df6a3f8", + "sha256:c68e820879ff39992c7f148113b46efcd6ec765a4865581f2902b3c43a5f4bbb", + "sha256:c77494a2f2282d9bbbbcab7c227a4d1b4bb829875c96251f66fb5f3bae4fb053", + "sha256:c998d0558805860503bc3a595994895ca0f7835e00668dadc673bbf7f5fbfcbe", + "sha256:ccad2800dfdff34392448c4bf834be124f10a5bc102f254521d931c1c53c455a", + "sha256:cd126498171f752dd85737ab1544329a4520c53eed3997f9b08aefbafb1cc53b", + "sha256:ce44217ad99ffad8027d2fde0269ae368c86db66ea0571c62a000798d69401fb", + "sha256:d1ac2bc069f4a458634c26b101c2341b18da85cb96afe0015990507efec2e417", + "sha256:d417a4f6943112fae3924bae2af7112562285848d9bcee737fc4ff7cbd450e6c", + "sha256:d538df442c0d9665664ab6dd5fccd0110fa3b364914f9c85b3ef9b7b2e157980", + "sha256:ded1b1803151dd0f20a8945508786d57c2f97a50289b16f2629f85433e546d47", + "sha256:e2e93b88ecc8f74074012e18d679fb2e9c746f2a56f79cd5e2b1afcf2a8a786b", + "sha256:e4ca3b9f370f218cc2a0309542cab8d0acdfd66667e7c37d04d617012485f904", + "sha256:e4ee8b8639070ff246ad3649294336b06db37a94bdea0d09ea491603e0be73b8", + "sha256:e52f77a0cd246086afde8815039f3e16f8d2be51786c0a39b57104c563c5cbb0", + "sha256:eaea112aed589131f73d50d570a6864728bd7c0c66ef6c9154ed7b59f24da611", + "sha256:ed20a4bdc635f36cb19e630bfc644181dd075839b6fc84cac51c0f381ac472e2", + "sha256:eedc3f247ee7b3808ea07205f3e7d7879bc19ad3e6222195cd5fbf9988853e4d", + "sha256:f0e1844ad47c7bd5d6fa784f1d4accc5f4168b48999303a868fe0f8597bde715", + "sha256:f4fe99ce44128c71233d0d72152db31ca119711dfc5f2c82385ad611d8d7f897", + "sha256:f8cfd847e6b9ecf9f2f2531c8427035f291ec286c0a4944b0a9fce58c6446046", + "sha256:f9ca0e6ce7774dc7830dc0cc4bb6b3eec769db667f230e7c770a628c1aa5681b", + "sha256:fa2bea05ff0a8fb4d8124498e00e02398f06d23cdadd0fe027d84a3f7afde31e", + "sha256:fbbb63bed5fcd70cd3dd23a087cd78e4675fb5a2963b8af53f945cbbca79ae16", + "sha256:fbda058a9a68bec347962595f50546a8a4a34fd7b0654a7b9697917dc2bf810d", + "sha256:ffd591e22b22f9cb48e472529db6a47203c41c2c5911ff0a52e85723196c0d75" ], - "markers": "python_version >= '3.7'", - "version": "==1.9.4" + "markers": "python_version >= '3.8'", + "version": "==1.15.2" } }, "develop": { "coverage": { "hashes": [ - "sha256:018a12985185038a5b2bcafab04ab833a9a0f2c59995b3cec07e10074c78635f", - "sha256:02ff6e898197cc1e9fa375581382b72498eb2e6d5fc0b53f03e496cfee3fac6d", - "sha256:042183de01f8b6d531e10c197f7f0315a61e8d805ab29c5f7b51a01d62782747", - "sha256:1014fbf665fef86cdfd6cb5b7371496ce35e4d2a00cda501cf9f5b9e6fced69f", - "sha256:1137f46adb28e3813dec8c01fefadcb8c614f33576f672962e323b5128d9a68d", - "sha256:16852febd96acd953b0d55fc842ce2dac1710f26729b31c80b940b9afcd9896f", - "sha256:2174e7c23e0a454ffe12267a10732c273243b4f2d50d07544a91198f05c48f47", - "sha256:2214ee920787d85db1b6a0bd9da5f8503ccc8fcd5814d90796c2f2493a2f4d2e", - "sha256:3257fdd8e574805f27bb5342b77bc65578e98cbc004a92232106344053f319ba", - "sha256:3684bc2ff328f935981847082ba4fdc950d58906a40eafa93510d1b54c08a66c", - "sha256:3a6612c99081d8d6134005b1354191e103ec9705d7ba2754e848211ac8cacc6b", - "sha256:3d7564cc09dd91b5a6001754a5b3c6ecc4aba6323baf33a12bd751036c998be4", - "sha256:44da56a2589b684813f86d07597fdf8a9c6ce77f58976727329272f5a01f99f7", - "sha256:5013ed890dc917cef2c9f765c4c6a8ae9df983cd60dbb635df8ed9f4ebc9f555", - "sha256:54317c2b806354cbb2dc7ac27e2b93f97096912cc16b18289c5d4e44fc663233", - "sha256:56b4eafa21c6c175b3ede004ca12c653a88b6f922494b023aeb1e836df953ace", - "sha256:581ea96f92bf71a5ec0974001f900db495488434a6928a2ca7f01eee20c23805", - "sha256:5cd64adedf3be66f8ccee418473c2916492d53cbafbfcff851cbec5a8454b136", - "sha256:5df54843b88901fdc2f598ac06737f03d71168fd1175728054c8f5a2739ac3e4", - "sha256:65e528e2e921ba8fd67d9055e6b9f9e34b21ebd6768ae1c1723f4ea6ace1234d", - "sha256:6aae5cce399a0f065da65c7bb1e8abd5c7a3043da9dceb429ebe1b289bc07806", - "sha256:6cfb5a4f556bb51aba274588200a46e4dd6b505fb1a5f8c5ae408222eb416f99", - "sha256:7076b4b3a5f6d2b5d7f1185fde25b1e54eb66e647a1dfef0e2c2bfaf9b4c88c8", - "sha256:73ca8fbc5bc622e54627314c1a6f1dfdd8db69788f3443e752c215f29fa87a0b", - "sha256:79b356f3dd5b26f3ad23b35c75dbdaf1f9e2450b6bcefc6d0825ea0aa3f86ca5", - "sha256:7a892be37ca35eb5019ec85402c3371b0f7cda5ab5056023a7f13da0961e60da", - "sha256:8192794d120167e2a64721d88dbd688584675e86e15d0569599257566dec9bf0", - "sha256:820bc841faa502e727a48311948e0461132a9c8baa42f6b2b84a29ced24cc078", - "sha256:8f894208794b164e6bd4bba61fc98bf6b06be4d390cf2daacfa6eca0a6d2bb4f", - "sha256:a04e990a2a41740b02d6182b498ee9796cf60eefe40cf859b016650147908029", - "sha256:a44963520b069e12789d0faea4e9fdb1e410cdc4aab89d94f7f55cbb7fef0353", - "sha256:a6bb74ed465d5fb204b2ec41d79bcd28afccf817de721e8a807d5141c3426638", - "sha256:ab73b35e8d109bffbda9a3e91c64e29fe26e03e49addf5b43d85fc426dde11f9", - "sha256:aea072a941b033813f5e4814541fc265a5c12ed9720daef11ca516aeacd3bd7f", - "sha256:b1ccf5e728ccf83acd313c89f07c22d70d6c375a9c6f339233dcf792094bcbf7", - "sha256:b385d49609f8e9efc885790a5a0e89f2e3ae042cdf12958b6034cc442de428d3", - "sha256:b3d45ff86efb129c599a3b287ae2e44c1e281ae0f9a9bad0edc202179bcc3a2e", - "sha256:b4a474f799456e0eb46d78ab07303286a84a3140e9700b9e154cfebc8f527016", - "sha256:b95c3a8cb0463ba9f77383d0fa8c9194cf91f64445a63fc26fb2327e1e1eb088", - "sha256:c5986ee7ea0795a4095ac4d113cbb3448601efca7f158ec7f7087a6c705304e4", - "sha256:cdd31315fc20868c194130de9ee6bfd99755cc9565edff98ecc12585b90be882", - "sha256:cef4649ec906ea7ea5e9e796e68b987f83fa9a718514fe147f538cfeda76d7a7", - "sha256:d05c16cf4b4c2fc880cb12ba4c9b526e9e5d5bb1d81313d4d732a5b9fe2b9d53", - "sha256:d2e344d6adc8ef81c5a233d3a57b3c7d5181f40e79e05e1c143da143ccb6377d", - "sha256:d45d3cbd94159c468b9b8c5a556e3f6b81a8d1af2a92b77320e887c3e7a5d080", - "sha256:db14f552ac38f10758ad14dd7b983dbab424e731588d300c7db25b6f89e335b5", - "sha256:dbc5958cb471e5a5af41b0ddaea96a37e74ed289535e8deca404811f6cb0bc3d", - "sha256:ddbd2f9713a79e8e7242d7c51f1929611e991d855f414ca9996c20e44a895f7c", - "sha256:e16f3d6b491c48c5ae726308e6ab1e18ee830b4cdd6913f2d7f77354b33f91c8", - "sha256:e2afe743289273209c992075a5a4913e8d007d569a406ffed0bd080ea02b0633", - "sha256:e564c2cf45d2f44a9da56f4e3a26b2236504a496eb4cb0ca7221cd4cc7a9aca9", - "sha256:ed550e7442f278af76d9d65af48069f1fb84c9f745ae249c1a183c1e9d1b025c" + "sha256:04f2189716e85ec9192df307f7c255f90e78b6e9863a03223c3b998d24a3c6c6", + "sha256:0c6c0f4d53ef603397fc894a895b960ecd7d44c727df42a8d500031716d4e8d2", + "sha256:0ca37993206402c6c35dc717f90d4c8f53568a8b80f0bf1a1b2b334f4d488fba", + "sha256:12f9515d875859faedb4144fd38694a761cd2a61ef9603bf887b13956d0bbfbb", + "sha256:1990b1f4e2c402beb317840030bb9f1b6a363f86e14e21b4212e618acdfce7f6", + "sha256:2341a78ae3a5ed454d524206a3fcb3cec408c2a0c7c2752cd78b606a2ff15af4", + "sha256:23bb63ae3f4c645d2d82fa22697364b0046fbafb6261b258a58587441c5f7bd0", + "sha256:27bd5f18d8f2879e45724b0ce74f61811639a846ff0e5c0395b7818fae87aec6", + "sha256:2dc7d6b380ca76f5e817ac9eef0c3686e7834c8346bef30b041a4ad286449990", + "sha256:331b200ad03dbaa44151d74daeb7da2cf382db424ab923574f6ecca7d3b30de3", + "sha256:365defc257c687ce3e7d275f39738dcd230777424117a6c76043459db131dd43", + "sha256:37be7b5ea3ff5b7c4a9db16074dc94523b5f10dd1f3b362a827af66a55198175", + "sha256:3c2e6fa98032fec8282f6b27e3f3986c6e05702828380618776ad794e938f53a", + "sha256:40e8b1983080439d4802d80b951f4a93d991ef3261f69e81095a66f86cf3c3c6", + "sha256:43517e1f6b19f610a93d8227e47790722c8bf7422e46b365e0469fc3d3563d97", + "sha256:43b32a06c47539fe275106b376658638b418c7cfdfff0e0259fbf877e845f14b", + "sha256:43d6a66e33b1455b98fc7312b124296dad97a2e191c80320587234a77b1b736e", + "sha256:4c59d6a4a4633fad297f943c03d0d2569867bd5372eb5684befdff8df8522e39", + "sha256:52ac29cc72ee7e25ace7807249638f94c9b6a862c56b1df015d2b2e388e51dbd", + "sha256:54356a76b67cf8a3085818026bb556545ebb8353951923b88292556dfa9f812d", + "sha256:583049c63106c0555e3ae3931edab5669668bbef84c15861421b94e121878d3f", + "sha256:6d99198203f0b9cb0b5d1c0393859555bc26b548223a769baf7e321a627ed4fc", + "sha256:6da42bbcec130b188169107ecb6ee7bd7b4c849d24c9370a0c884cf728d8e976", + "sha256:6e484e479860e00da1f005cd19d1c5d4a813324e5951319ac3f3eefb497cc549", + "sha256:70a6756ce66cd6fe8486c775b30889f0dc4cb20c157aa8c35b45fd7868255c5c", + "sha256:70d24936ca6c15a3bbc91ee9c7fc661132c6f4c9d42a23b31b6686c05073bde5", + "sha256:71967c35828c9ff94e8c7d405469a1fb68257f686bca7c1ed85ed34e7c2529c4", + "sha256:79644f68a6ff23b251cae1c82b01a0b51bc40c8468ca9585c6c4b1aeee570e0b", + "sha256:87cd2e29067ea397a47e352efb13f976eb1b03e18c999270bb50589323294c6e", + "sha256:8d4c6ea0f498c7c79111033a290d060c517853a7bcb2f46516f591dab628ddd3", + "sha256:9134032f5aa445ae591c2ba6991d10136a1f533b1d2fa8f8c21126468c5025c6", + "sha256:921fbe13492caf6a69528f09d5d7c7d518c8d0e7b9f6701b7719715f29a71e6e", + "sha256:99670790f21a96665a35849990b1df447993880bb6463a0a1d757897f30da929", + "sha256:9975442f2e7a5cfcf87299c26b5a45266ab0696348420049b9b94b2ad3d40234", + "sha256:99ded130555c021d99729fabd4ddb91a6f4cc0707df4b1daf912c7850c373b13", + "sha256:a3328c3e64ea4ab12b85999eb0779e6139295bbf5485f69d42cf794309e3d007", + "sha256:a4fb91d5f72b7e06a14ff4ae5be625a81cd7e5f869d7a54578fc271d08d58ae3", + "sha256:aa23ce39661a3e90eea5f99ec59b763b7d655c2cada10729ed920a38bfc2b167", + "sha256:aac7501ae73d4a02f4b7ac8fcb9dc55342ca98ffb9ed9f2dfb8a25d53eda0e4d", + "sha256:ab84a8b698ad5a6c365b08061920138e7a7dd9a04b6feb09ba1bfae68346ce6d", + "sha256:b4adeb878a374126f1e5cf03b87f66279f479e01af0e9a654cf6d1509af46c40", + "sha256:b9853509b4bf57ba7b1f99b9d866c422c9c5248799ab20e652bbb8a184a38181", + "sha256:bb7d5fe92bd0dc235f63ebe9f8c6e0884f7360f88f3411bfed1350c872ef2054", + "sha256:bca4c8abc50d38f9773c1ec80d43f3768df2e8576807d1656016b9d3eeaa96fd", + "sha256:c222958f59b0ae091f4535851cbb24eb57fc0baea07ba675af718fb5302dddb2", + "sha256:c30e42ea11badb147f0d2e387115b15e2bd8205a5ad70d6ad79cf37f6ac08c91", + "sha256:c3a79f56dee9136084cf84a6c7c4341427ef36e05ae6415bf7d787c96ff5eaa3", + "sha256:c51ef82302386d686feea1c44dbeef744585da16fcf97deea2a8d6c1556f519b", + "sha256:c77326300b839c44c3e5a8fe26c15b7e87b2f32dfd2fc9fee1d13604347c9b38", + "sha256:d33a785ea8354c480515e781554d3be582a86297e41ccbea627a5c632647f2cd", + "sha256:d546cfa78844b8b9c1c0533de1851569a13f87449897bbc95d698d1d3cb2a30f", + "sha256:da29ceabe3025a1e5a5aeeb331c5b1af686daab4ff0fb4f83df18b1180ea83e2", + "sha256:df8c05a0f574d480947cba11b947dc41b1265d721c3777881da2fb8d3a1ddfba", + "sha256:e266af4da2c1a4cbc6135a570c64577fd3e6eb204607eaff99d8e9b710003c6f", + "sha256:e279f3db904e3b55f520f11f983cc8dc8a4ce9b65f11692d4718ed021ec58b83", + "sha256:ea52bd218d4ba260399a8ae4bb6b577d82adfc4518b93566ce1fddd4a49d1dce", + "sha256:ebec65f5068e7df2d49466aab9128510c4867e532e07cb6960075b27658dca38", + "sha256:ec1e3b40b82236d100d259854840555469fad4db64f669ab817279eb95cd535c", + "sha256:ee77c7bef0724165e795b6b7bf9c4c22a9b8468a6bdb9c6b4281293c6b22a90f", + "sha256:f263b18692f8ed52c8de7f40a0751e79015983dbd77b16906e5b310a39d3ca21", + "sha256:f7b26757b22faf88fcf232f5f0e62f6e0fd9e22a8a5d0d5016888cdfe1f6c1c4", + "sha256:f7ddb920106bbbbcaf2a274d56f46956bf56ecbde210d88061824a95bdd94e92" ], "index": "pypi", - "version": "==7.5.4" + "markers": "python_version >= '3.9'", + "version": "==7.6.3" }, "iniconfig": { "hashes": [ @@ -1126,11 +1349,12 @@ }, "pytest": { "hashes": [ - "sha256:c434598117762e2bd304e526244f67bf66bbd7b5d6cf22138be51ff661980343", - "sha256:de4bb8104e201939ccdc688b27a89a7be2079b22e2bd2b07f806b6ba71117977" + "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181", + "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2" ], "index": "pypi", - "version": "==8.2.2" + "markers": "python_version >= '3.8'", + "version": "==8.3.3" } } } diff --git a/dbrepo-search-service/init/README.md b/dbrepo-search-service/init/README.md index 74767ea02ada906b7f7feab0e13a7c4b1fe9a7d1..a188e561c737ddcc9bb772099dcfe51e5d8e9323 100644 --- a/dbrepo-search-service/init/README.md +++ b/dbrepo-search-service/init/README.md @@ -4,4 +4,8 @@ Responsible for: * Creating `database` index if not existing * Importing database(s) from the Metadata Database -* Exit \ No newline at end of file +* Exit + +## Development + +Open in `./dbrepo-search-service` directory (depends on `clients` package). \ No newline at end of file diff --git a/dbrepo-search-service/init/app.py b/dbrepo-search-service/init/app.py index fccbd92feaf8f9e3e904ca245e485ff4b8f8aa8e..9fe915f92c50d2b712058783d4eecf1b087cc8f7 100644 --- a/dbrepo-search-service/init/app.py +++ b/dbrepo-search-service/init/app.py @@ -48,11 +48,11 @@ class App: search_instance: OpenSearch = None def __init__(self): - self.metadata_service_endpoint = os.getenv("METADATA_SERVICE_ENDPOINT") - self.search_host = os.getenv("OPENSEARCH_HOST") - self.search_port = int(os.getenv("OPENSEARCH_PORT")) - self.search_username = os.getenv("OPENSEARCH_USERNAME") - self.search_password = os.getenv("OPENSEARCH_PASSWORD") + self.metadata_service_endpoint = os.getenv("METADATA_SERVICE_ENDPOINT", "http://metadata-service:8080") + self.search_host = os.getenv("OPENSEARCH_HOST", "search-db") + self.search_port = int(os.getenv("OPENSEARCH_PORT", "9200")) + self.search_username = os.getenv("OPENSEARCH_USERNAME", "admin") + self.search_password = os.getenv("OPENSEARCH_PASSWORD", "admin") def _instance(self) -> OpenSearch: """ @@ -67,9 +67,6 @@ class App: logging.debug(f"create instance {self.search_host}:{self.search_port}") return self.search_instance - def index_exists(self): - return self._instance().indices.exists(index="database") - def database_exists(self, database_id: int): try: self._instance().get(index="database", id=database_id) @@ -77,40 +74,26 @@ class App: except opensearchpy.exceptions.NotFoundError: return False - def index_update(self, is_created: bool) -> bool: - """ - - :param is_created: - :return: True if the index was updated - """ - if is_created: - logging.debug(f"index 'database' does not exist, creating...") - with open('./database.json', 'r') as f: - self._instance().indices.create(index="database", body=json.load(f)) - logging.info(f"Created index 'database'") - return True - mapping = dict(self._instance().indices.get_mapping(index="database")) - identifier_props = mapping["database"]["mappings"]["properties"]["identifiers"]["properties"] - if "status" in identifier_props: - logging.debug(f"found mapping database.identifiers.status: detected current mapping") - return False - logging.debug(f"index 'database' exists, updating mapping...") + def index_update(self) -> None: + if self._instance().indices.exists(index="database"): + logging.debug(f"index 'database' exists, removing...") + self._instance().indices.delete(index="database") with open('./database.json', 'r') as f: - self._instance().indices.put_mapping(index="database", body=json.load(f)) - logging.info(f"Updated index 'database'") - return True + self._instance().indices.create(index="database", body=json.load(f)) + logging.info(f"Created index 'database'") def fetch_databases(self) -> List[Database]: + logging.debug(f"fetching database from endpoint: {self.metadata_service_endpoint}") client = RestClient(endpoint=self.metadata_service_endpoint) databases = [] - for database in client.get_databases(): + for index, database in enumerate(client.get_databases()): + logging.debug(f"fetching database {index}/{len(databases)} details for database id: {database.id}") databases.append(client.get_database(database_id=database.id)) logging.debug(f"fetched {len(databases)} database(s)") return databases def save_databases(self, databases: List[Database]): - logging.debug( - f"save {len(databases)} database(s)") + logging.debug(f"save {len(databases)} database(s)") for doc in databases: doc: Database = doc try: @@ -124,7 +107,6 @@ class App: if __name__ == "__main__": app = App() - create = not app.index_exists() - update = app.index_update(is_created=create) + update = app.index_update() app.save_databases(databases=app.fetch_databases()) logging.info("Finished. Exiting.") diff --git a/dbrepo-search-service/clients/keycloak_client.py b/dbrepo-search-service/init/clients/keycloak_client.py similarity index 100% rename from dbrepo-search-service/clients/keycloak_client.py rename to dbrepo-search-service/init/clients/keycloak_client.py diff --git a/dbrepo-search-service/clients/opensearch_client.py b/dbrepo-search-service/init/clients/opensearch_client.py similarity index 89% rename from dbrepo-search-service/clients/opensearch_client.py rename to dbrepo-search-service/init/clients/opensearch_client.py index 3f198ac443784286c4c16912d1e2d946f1fd9080..7d25fcded5a29e87524523785133d7aaa56f314d 100644 --- a/dbrepo-search-service/clients/opensearch_client.py +++ b/dbrepo-search-service/init/clients/opensearch_client.py @@ -1,14 +1,14 @@ """ The opensearch_client.py is used by the different API endpoints in routes.py to handle requests to the opensearch db """ +import os from json import dumps, load import logging from dbrepo.api.dto import Database -from flask import current_app from collections.abc import MutableMapping -from opensearchpy import OpenSearch, TransportError, RequestError +from opensearchpy import OpenSearch, TransportError, RequestError, NotFoundError from omlib.measure import om from omlib.constants import OM_IDS @@ -26,11 +26,11 @@ class OpenSearchClient: password: str = None instance: OpenSearch = None - def __init__(self): - self.host = current_app.config["OPENSEARCH_HOST"] - self.port = int(current_app.config["OPENSEARCH_PORT"]) - self.username = current_app.config["OPENSEARCH_USERNAME"] - self.password = current_app.config["OPENSEARCH_PASSWORD"] + def __init__(self, host: str = None, port: int = None, username: str = None, password: str = None): + self.host = os.getenv('OPENSEARCH_HOST', host) + self.port = int(os.getenv('OPENSEARCH_PORT', port)) + self.username = os.getenv('OPENSEARCH_USERNAME', username) + self.password = os.getenv('OPENSEARCH_PASSWORD', password) def _instance(self) -> OpenSearch: """ @@ -42,7 +42,6 @@ class OpenSearchClient: self.instance = OpenSearch(hosts=[{"host": self.host, "port": self.port}], http_compress=True, http_auth=(self.username, self.password)) - logging.debug(f"create instance {self.host}:{self.port}") return self.instance def get_database(self, database_id: int) -> Database: @@ -68,16 +67,8 @@ class OpenSearchClient: @throws: opensearchpy.exceptions.NotFoundError If the database was not found in the Search Database. """ logging.debug(f"updating database with id: {database_id} in search database") - try: - self._instance().index(index="database", id=database_id, body=dumps(data.model_dump())) - except RequestError as e: - logging.error(f"Failed to update in search database: {e.info}") - raise e - try: - response: dict = self._instance().get(index="database", id=database_id) - except TransportError as e: - logging.error(f"Failed to get updated database in search database: {e.status_code}") - raise e + self._instance().index(index="database", id=database_id, body=dumps(data.model_dump())) + response: dict = self._instance().get(index="database", id=database_id) database = Database.parse_obj(response["_source"]) logging.info(f"Updated database with id {database_id} in index 'database'") return database @@ -119,10 +110,10 @@ class OpenSearchClient: results = [hit["_source"] for hit in response["hits"]["hits"]] return results - def get_fields_for_index(self, type: str): + def get_fields_for_index(self, field_type: str): """ returns a list of attributes of the data for a specific index. - :param type: The search type + :param field_type: The search type :return: list of fields """ fields = { @@ -135,8 +126,10 @@ class OpenSearchClient: "view": "views.*", "user": "creator.*", } - logging.debug(f'requesting field(s) {fields[type]} for filter: {type}') - fields = self._instance().indices.get_field_mapping(fields[type]) + if field_type not in fields.keys(): + raise NotFoundError(f"Failed to find field type: {field_type}") + logging.debug(f'requesting field(s) {fields[field_type]} for filter: {field_type}') + fields = self._instance().indices.get_field_mapping(fields[field_type]) fields_list = [] fd = flatten_dict(fields) for key in fd.keys(): @@ -170,13 +163,13 @@ class OpenSearchClient: logging.info(f"Found {len(response['hits']['hits'])} result(s)") return response - def general_search(self, type: str = None, field_value_pairs: dict = None): + def general_search(self, field_type: str = None, field_value_pairs: dict = None): """ Main method for searching stuff in the opensearch db all parameters are optional - :param type: The index to be searched. Optional. + :param field_type: The index to be searched. Optional. :param field_value_pairs: The key-value pair of properties that need to match. Optional. :return: The object of results and HTTP status code. e.g. { "hits": { "hits": [] } }, 200 """ @@ -205,7 +198,7 @@ class OpenSearchClient: body = { "query": {"bool": {"must": musts}} } - logging.debug(f'search in index database for type: {type}') + logging.debug(f'search in index database for type: {field_type}') logging.debug(f'search body: {dumps(body)}') response = self._instance().search( index="database", @@ -214,12 +207,10 @@ class OpenSearchClient: results = [hit["_source"] for hit in response["hits"]["hits"]] return results - def unit_independent_search(self, t1=None, t2=None, field_value_pairs=None): + def unit_independent_search(self, t1: float, t2: float, field_value_pairs): """ Main method for searching stuff in the opensearch db - all parameters are optional - :param t1: start value :param t2: end value :param field_value_pairs: the key-value pairs @@ -241,6 +232,8 @@ class OpenSearchClient: ) unit_uris = [hit["key"] for hit in response["aggregations"]["units"]["buckets"]] logging.debug(f"found {len(unit_uris)} unit(s) in column index") + if len(unit_uris) == 0: + raise NotFoundError("Failed to search: no unit assigned") base_unit = unit_uri_to_unit(field_value_pairs["unit.uri"]) for unit_uri in unit_uris: gte = t1 diff --git a/dbrepo-search-service/init/database.json b/dbrepo-search-service/init/database.json index d87d33b5e29abae3ffbb9beab8bad45a00d0ff56..1e6bdd0c4c4d3f2302bafc4c7a79bed2ec84224d 100644 --- a/dbrepo-search-service/init/database.json +++ b/dbrepo-search-service/init/database.json @@ -125,40 +125,6 @@ }, "image": { "properties": { - "date_formats": { - "properties": { - "created_at": { - "type": "date" - }, - "database_format": { - "type": "text", - "fields": { - "keyword": { - "type": "keyword", - "ignore_above": 256 - } - } - }, - "has_time": { - "type": "boolean" - }, - "id": { - "type": "long" - }, - "unix_format": { - "type": "text", - "fields": { - "keyword": { - "type": "keyword", - "ignore_above": 256 - } - } - } - } - }, - "default_port": { - "type": "long" - }, "dialect": { "type": "text", "fields": { @@ -639,37 +605,6 @@ "database_id": { "type": "long" }, - "date_format": { - "properties": { - "created_at": { - "type": "date" - }, - "database_format": { - "type": "text", - "fields": { - "keyword": { - "type": "keyword", - "ignore_above": 256 - } - } - }, - "has_time": { - "type": "boolean" - }, - "id": { - "type": "long" - }, - "unix_format": { - "type": "text", - "fields": { - "keyword": { - "type": "keyword", - "ignore_above": 256 - } - } - } - } - }, "id": { "type": "long" }, @@ -959,37 +894,6 @@ "database_id": { "type": "long" }, - "date_format": { - "properties": { - "created_at": { - "type": "date" - }, - "database_format": { - "type": "text", - "fields": { - "keyword": { - "type": "keyword", - "ignore_above": 256 - } - } - }, - "has_time": { - "type": "boolean" - }, - "id": { - "type": "long" - }, - "unix_format": { - "type": "text", - "fields": { - "keyword": { - "type": "keyword", - "ignore_above": 256 - } - } - } - } - }, "id": { "type": "long" }, diff --git a/dbrepo-search-service/init/lib/dbrepo-1.4.4-py3-none-any.whl b/dbrepo-search-service/init/lib/dbrepo-1.4.4-py3-none-any.whl deleted file mode 100644 index 617969c3eb15926d932b7c0180bed51b9ef7052d..0000000000000000000000000000000000000000 Binary files a/dbrepo-search-service/init/lib/dbrepo-1.4.4-py3-none-any.whl and /dev/null differ diff --git a/dbrepo-search-service/init/lib/dbrepo-1.4.4.tar.gz b/dbrepo-search-service/init/lib/dbrepo-1.4.4.tar.gz deleted file mode 100644 index 9d1d5ae238baba6bc51db4d219a0d09b5aca1c51..0000000000000000000000000000000000000000 Binary files a/dbrepo-search-service/init/lib/dbrepo-1.4.4.tar.gz and /dev/null differ diff --git a/dbrepo-search-service/init/lib/dbrepo-1.4.5-py3-none-any.whl b/dbrepo-search-service/init/lib/dbrepo-1.4.5-py3-none-any.whl deleted file mode 100644 index 249fd5dc181271a3069745f5a6ef8a26de398037..0000000000000000000000000000000000000000 Binary files a/dbrepo-search-service/init/lib/dbrepo-1.4.5-py3-none-any.whl and /dev/null differ diff --git a/dbrepo-search-service/init/lib/dbrepo-1.4.5.tar.gz b/dbrepo-search-service/init/lib/dbrepo-1.4.5.tar.gz deleted file mode 100644 index 2f21496bd2280550f4242bbc0fff4a47116d6ad5..0000000000000000000000000000000000000000 Binary files a/dbrepo-search-service/init/lib/dbrepo-1.4.5.tar.gz and /dev/null differ diff --git a/dbrepo-search-service/init/lib/dbrepo-1.4.7.tar.gz b/dbrepo-search-service/init/lib/dbrepo-1.4.7.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..c652dbae4a60aae708eb6fe4e751977b97b72344 Binary files /dev/null and b/dbrepo-search-service/init/lib/dbrepo-1.4.7.tar.gz differ diff --git a/dbrepo-search-service/omlib/__init__.py b/dbrepo-search-service/init/omlib/__init__.py similarity index 100% rename from dbrepo-search-service/omlib/__init__.py rename to dbrepo-search-service/init/omlib/__init__.py diff --git a/dbrepo-search-service/omlib/constants.py b/dbrepo-search-service/init/omlib/constants.py similarity index 100% rename from dbrepo-search-service/omlib/constants.py rename to dbrepo-search-service/init/omlib/constants.py diff --git a/dbrepo-search-service/omlib/dimension.py b/dbrepo-search-service/init/omlib/dimension.py similarity index 100% rename from dbrepo-search-service/omlib/dimension.py rename to dbrepo-search-service/init/omlib/dimension.py diff --git a/dbrepo-search-service/omlib/exceptions/__init__.py b/dbrepo-search-service/init/omlib/exceptions/__init__.py similarity index 100% rename from dbrepo-search-service/omlib/exceptions/__init__.py rename to dbrepo-search-service/init/omlib/exceptions/__init__.py diff --git a/dbrepo-search-service/omlib/exceptions/dimensionexception.py b/dbrepo-search-service/init/omlib/exceptions/dimensionexception.py similarity index 100% rename from dbrepo-search-service/omlib/exceptions/dimensionexception.py rename to dbrepo-search-service/init/omlib/exceptions/dimensionexception.py diff --git a/dbrepo-search-service/omlib/exceptions/unitconversionexception.py b/dbrepo-search-service/init/omlib/exceptions/unitconversionexception.py similarity index 100% rename from dbrepo-search-service/omlib/exceptions/unitconversionexception.py rename to dbrepo-search-service/init/omlib/exceptions/unitconversionexception.py diff --git a/dbrepo-search-service/omlib/exceptions/unitidentityexception.py b/dbrepo-search-service/init/omlib/exceptions/unitidentityexception.py similarity index 100% rename from dbrepo-search-service/omlib/exceptions/unitidentityexception.py rename to dbrepo-search-service/init/omlib/exceptions/unitidentityexception.py diff --git a/dbrepo-search-service/omlib/measure.py b/dbrepo-search-service/init/omlib/measure.py similarity index 100% rename from dbrepo-search-service/omlib/measure.py rename to dbrepo-search-service/init/omlib/measure.py diff --git a/dbrepo-search-service/omlib/omconstants.py b/dbrepo-search-service/init/omlib/omconstants.py similarity index 100% rename from dbrepo-search-service/omlib/omconstants.py rename to dbrepo-search-service/init/omlib/omconstants.py diff --git a/dbrepo-search-service/omlib/rdf/__init__.py b/dbrepo-search-service/init/omlib/rdf/__init__.py similarity index 100% rename from dbrepo-search-service/omlib/rdf/__init__.py rename to dbrepo-search-service/init/omlib/rdf/__init__.py diff --git a/dbrepo-search-service/omlib/rdf/om-2.0.rdf b/dbrepo-search-service/init/omlib/rdf/om-2.0.rdf similarity index 100% rename from dbrepo-search-service/omlib/rdf/om-2.0.rdf rename to dbrepo-search-service/init/omlib/rdf/om-2.0.rdf diff --git a/dbrepo-search-service/omlib/scale.py b/dbrepo-search-service/init/omlib/scale.py similarity index 100% rename from dbrepo-search-service/omlib/scale.py rename to dbrepo-search-service/init/omlib/scale.py diff --git a/dbrepo-search-service/omlib/thing.py b/dbrepo-search-service/init/omlib/thing.py similarity index 100% rename from dbrepo-search-service/omlib/thing.py rename to dbrepo-search-service/init/omlib/thing.py diff --git a/dbrepo-search-service/omlib/unit.py b/dbrepo-search-service/init/omlib/unit.py similarity index 100% rename from dbrepo-search-service/omlib/unit.py rename to dbrepo-search-service/init/omlib/unit.py diff --git a/dbrepo-search-service/init/test/conftest.py b/dbrepo-search-service/init/test/conftest.py new file mode 100644 index 0000000000000000000000000000000000000000..e2a00b1d86a7129935c7dbd42acb4a51254d3dbc --- /dev/null +++ b/dbrepo-search-service/init/test/conftest.py @@ -0,0 +1,47 @@ +import logging +import os + +import pytest +import json + +from testcontainers.opensearch import OpenSearchContainer + + +@pytest.fixture(scope="session", autouse=True) +def session(request): + """ + Create one OpenSearch container per test run only (admin:admin) + :param request: / + :return: The OpenSearch container + """ + logging.debug("[fixture] creating opensearch container") + container = OpenSearchContainer() + logging.debug("[fixture] starting opensearch container") + container.start() + + os.environ['OPENSEARCH_HOST'] = container.get_container_host_ip() + os.environ['OPENSEARCH_PORT'] = container.get_exposed_port(9200) + os.environ['OPENSEARCH_USERNAME'] = 'admin' + os.environ['OPENSEARCH_PASSWORD'] = 'admin' + + # destructor + def stop_opensearch(): + container.stop() + + request.addfinalizer(stop_opensearch) + return container + + +@pytest.fixture(scope="function", autouse=True) +def cleanup(request, session): + """ + Clean up after each test by removing the index and re-adding it (=so it's empty again) + :param request: / + :param session: / + :return: + """ + logging.info("[fixture] clean schema") + with open('./database.json', 'r') as f: + if session.get_client().indices.exists(index="database"): + session.get_client().indices.delete(index="database") + session.get_client().indices.create(index="database", body=json.load(f)) diff --git a/dbrepo-search-service/init/test/test_app.py b/dbrepo-search-service/init/test/test_app.py new file mode 100644 index 0000000000000000000000000000000000000000..118ccf99c16586e4305967ab22a12e6317fb8ae2 --- /dev/null +++ b/dbrepo-search-service/init/test/test_app.py @@ -0,0 +1,21 @@ +import unittest + +from app import App +from clients.opensearch_client import OpenSearchClient + + +class AppTest(unittest.TestCase): + + def test_index_update_succeeds(self): + # test + app = App() + app.index_update() + + def test_index_update_not_exists_succeeds(self): + # mock + client = OpenSearchClient() + client._instance().indices.delete(index="database") + + # test + app = App() + app.index_update() diff --git a/dbrepo-search-service/lib/dbrepo-1.4.4-py3-none-any.whl b/dbrepo-search-service/lib/dbrepo-1.4.4-py3-none-any.whl deleted file mode 100644 index 617969c3eb15926d932b7c0180bed51b9ef7052d..0000000000000000000000000000000000000000 Binary files a/dbrepo-search-service/lib/dbrepo-1.4.4-py3-none-any.whl and /dev/null differ diff --git a/dbrepo-search-service/lib/dbrepo-1.4.4.tar.gz b/dbrepo-search-service/lib/dbrepo-1.4.4.tar.gz deleted file mode 100644 index 9d1d5ae238baba6bc51db4d219a0d09b5aca1c51..0000000000000000000000000000000000000000 Binary files a/dbrepo-search-service/lib/dbrepo-1.4.4.tar.gz and /dev/null differ diff --git a/dbrepo-search-service/lib/dbrepo-1.4.5-py3-none-any.whl b/dbrepo-search-service/lib/dbrepo-1.4.5-py3-none-any.whl deleted file mode 100644 index 249fd5dc181271a3069745f5a6ef8a26de398037..0000000000000000000000000000000000000000 Binary files a/dbrepo-search-service/lib/dbrepo-1.4.5-py3-none-any.whl and /dev/null differ diff --git a/dbrepo-search-service/lib/dbrepo-1.4.5.tar.gz b/dbrepo-search-service/lib/dbrepo-1.4.5.tar.gz deleted file mode 100644 index 2f21496bd2280550f4242bbc0fff4a47116d6ad5..0000000000000000000000000000000000000000 Binary files a/dbrepo-search-service/lib/dbrepo-1.4.5.tar.gz and /dev/null differ diff --git a/dbrepo-search-service/lib/dbrepo-1.4.7.tar.gz b/dbrepo-search-service/lib/dbrepo-1.4.7.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..c652dbae4a60aae708eb6fe4e751977b97b72344 Binary files /dev/null and b/dbrepo-search-service/lib/dbrepo-1.4.7.tar.gz differ diff --git a/dbrepo-search-service/test/conftest.py b/dbrepo-search-service/test/conftest.py index 2a21f689702d7f78e14e73b6170715753e32b49c..1d603685d63e464a4ffe2f4aac005c2af319fc5a 100644 --- a/dbrepo-search-service/test/conftest.py +++ b/dbrepo-search-service/test/conftest.py @@ -1,8 +1,8 @@ import logging +import os import pytest -from app import app -from flask import current_app +import json from testcontainers.opensearch import OpenSearchContainer @@ -19,9 +19,10 @@ def session(request): logging.debug("[fixture] starting opensearch container") container.start() - with app.app_context(): - current_app.config['OPENSEARCH_HOST'] = container.get_container_host_ip() - current_app.config['OPENSEARCH_PORT'] = container.get_exposed_port(9200) + os.environ['OPENSEARCH_HOST'] = container.get_container_host_ip() + os.environ['OPENSEARCH_PORT'] = container.get_exposed_port(9200) + os.environ['OPENSEARCH_USERNAME'] = 'admin' + os.environ['OPENSEARCH_PASSWORD'] = 'admin' # destructor def stop_opensearch(): @@ -30,20 +31,17 @@ def session(request): request.addfinalizer(stop_opensearch) return container -# @pytest.fixture(scope="function", autouse=True) -# def cleanup(request, session): -# """ -# Clean up after each test by removing the buckets and re-adding them (=so they are empty again) -# :param request: / -# :param session: / -# :return: -# """ -# logging.info("[fixture] truncate buckets") -# for bucket in ["dbrepo-upload", "dbrepo-download"]: -# objects = [] -# for obj in session.get_client().list_objects(bucket): -# objects.append(DeleteObject(obj.object_name)) -# logging.info(f'request to remove objects {objects}') -# errors = session.get_client().remove_objects(bucket, objects) -# for error in errors: -# raise ConnectionError(f'Failed to delete object with key {error.object_name} of bucket {bucket}') + +@pytest.fixture(scope="function", autouse=True) +def cleanup(request, session): + """ + Clean up after each test by removing the index and re-adding it (=so it's empty again) + :param request: / + :param session: / + :return: + """ + logging.info("[fixture] clean schema") + with open('./init/database.json', 'r') as f: + if session.get_client().indices.exists(index="database"): + session.get_client().indices.delete(index="database") + session.get_client().indices.create(index="database", body=json.load(f)) diff --git a/dbrepo-search-service/test/rsa/rs256.key b/dbrepo-search-service/test/rsa/rs256.key new file mode 100644 index 0000000000000000000000000000000000000000..86b3eaf5c6c4c6b83071b6d1e9d69cb22bcd4085 --- /dev/null +++ b/dbrepo-search-service/test/rsa/rs256.key @@ -0,0 +1,3 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAqqnHQ2BWWW9vDNLRCcxD++xZg/16oqMo/c1l+lcFEjjAIJjJp/HqrPYU/U9GvquGE6PbVFtTzW1KcKawOW+FJNOA3CGo8Q1TFEfz43B8rZpKsFbJKvQGVv1Z4HaKPvLUm7iMm8Hv91cLduuoWx6Q3DPe2vg13GKKEZe7UFghF+0T9u8EKzA/XqQ0OiICmsmYPbwvf9N3bCKsB/Y10EYmZRb8IhCoV9mmO5TxgWgiuNeCTtNCv2ePYqL/U0WvyGFW0reasIK8eg3KrAUj8DpyOgPOVBn3lBGf+3KFSYi+0bwZbJZWqbC/Xlk20Go1YfeJPRIt7ImxD27R/lNjgDO/MwIDAQABAoIBADNcMt6hAHub4JTAYS6Mra0EPRBO2XhWmACBrv3+8ETClXd5475KPLDewgRVtlmtbwU8G8awUXESQgPS9lfiqvQhPreA3cHlm6oP2WMKOEtakr2s8I+frsTBLCo0Ini9RaSzjoVVgS0zofyhASKi+T970MafSj5P3XNb8YBFdXgoYDiA7FXLH6a/+m7LScL+wGcFMAAeYESxZbMQLfH3v8L+4EcTraiwjLG17ZdlF3dpybMyUSse6ZQ/PdlyvBuzzLXhN6Ce2gd9ATfS+YWTzo7Yf+GU+ex5bIpVOfHqtuM/hyq7YGKENClsXwNZIAoFnvGCbvECAfgyapVrD30IfykCgYEA0rgsSZ82pxT40NxwgBD1g9lbNVBKXphRB/3S078qusUzJjT7AldEj4imGPhAbI7bI8gAeWJsp1XJWkjM8ktaVrh+NQl7p8e9OPh0pQF/5Bdg8ajbjXESpjnaU66pVYRQy/d+jNli/YRAHX5RUfsBl+6W4+WSVMGmKBiqJsur+ecCgYEAz1YVXClcmUnyZem5B+2E9noIzjF6ROE+jIb6rawM85P3Xd0lXtECQavtxw+Qk7I32qOwrxl1UpK2foVel3pazi+4OpMfmqtYGenRP1Zk1cZwrDo0cIemTDGjj3kJ8tYn12CGolFQpJZgK6OHzvG0tOxI5VZgjIViWNPe1PGWXtUCgYEAxXGNDe8BZs1f11S2lUlOw5yGug3hoYFXbAWJ5p7Ziuf8ZXB/QlJDC7se54a11wKEk6Jzz0lKRgE8CjzszJuOqnN0zn10QGIIC7nCklo1W6QMUmPGVWH994N976tZP6gbjQL6sT+AYcvpx7j0ubxYYeRNvnz+ACzzY964kGGHY0ECgYEAumlwPPNnMN7+VEjGNm2D7UMdJZ3wi3tkjF5ThdA5uMohTsAk+FG80KSu3RmOaGyEsUwY7+VYyYvlDm4E9PZqLBVVczyR3rMNPAcwPd0EPfvzk7WlLkOX7ct3fehaXH3VRlyfz9KCSeh1wOZ/lT1VtpD2nVOC7PSDzs92+kfXZZ0CgYAnrD1y4skgXkdwolZ3unn3EFyGm2d+X5aMTHwQPdWxqoNIAl/9wdghlzihwnPhhsxq1WzlxuC3V2IMrNPtRx70Mi+FbSmR5m4Xx5RptgMtMlwno+L40PzNJgMjHGjt0wcx3Vel8wuohDtnqMyS7P5nG1/TQx0Cyzwn7QOXlNpgbQ== +-----END RSA PRIVATE KEY----- \ No newline at end of file diff --git a/dbrepo-search-service/test/rsa/rsa256.pkey b/dbrepo-search-service/test/rsa/rsa256.pkey new file mode 100644 index 0000000000000000000000000000000000000000..857dfb22beeac202c2955d7cc4f782b787492beb --- /dev/null +++ b/dbrepo-search-service/test/rsa/rsa256.pkey @@ -0,0 +1,3 @@ +-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqqnHQ2BWWW9vDNLRCcxD++xZg/16oqMo/c1l+lcFEjjAIJjJp/HqrPYU/U9GvquGE6PbVFtTzW1KcKawOW+FJNOA3CGo8Q1TFEfz43B8rZpKsFbJKvQGVv1Z4HaKPvLUm7iMm8Hv91cLduuoWx6Q3DPe2vg13GKKEZe7UFghF+0T9u8EKzA/XqQ0OiICmsmYPbwvf9N3bCKsB/Y10EYmZRb8IhCoV9mmO5TxgWgiuNeCTtNCv2ePYqL/U0WvyGFW0reasIK8eg3KrAUj8DpyOgPOVBn3lBGf+3KFSYi+0bwZbJZWqbC/Xlk20Go1YfeJPRIt7ImxD27R/lNjgDO/MwIDAQAB +-----END PUBLIC KEY----- diff --git a/dbrepo-search-service/test/run_testindicies.py b/dbrepo-search-service/test/run_testindicies.py deleted file mode 100644 index b547573dd65369cd88be1750f1224f05c333a883..0000000000000000000000000000000000000000 --- a/dbrepo-search-service/test/run_testindicies.py +++ /dev/null @@ -1,91 +0,0 @@ -""" -This script spins up docker containers running an opensearch db with predefined entries. -This is useful e.g. if you want to run tests on the functionality of the opensearch_client. - -note: The port of the test container should be 9200, but it's somehow kinda random, -and using environmet variables also doesn't really work, -so the correct port number is just saved in the .testpickle -""" - -from testcontainers.opensearch import OpenSearchContainer -import pprint -import time -import os -import pickle - - -doc1 = { - "author": "aaa", - "name": "Hi! My name is", - "description":"here's some description text", - "created": "2023-07-27", - "docID":1, - "public":True, - "details": { - "nestedObject1": "something", - "nestedObject2": "something else", - "evenMoreNested": { - "bla":"blib", - "blob":"blub" - } - } -} - -doc2 = { - "author": "max", - "name": "Bla Bla", - "public": False, - "description": "here's another description text, about a fictional entry with some random measurement data", - "created": "2023-07-27", - "docID":2, - "details": { - "nestedObject1": "something", - "nestedObject2": "something else" - } -} - -doc3 = { - "author": "mweise", - "name": "databaseName", - "public": True, - "description": "here is a really old entry", - "created":"2022-07-27", - "docID":3, - "details": { - "nestedObject1": "something", - "nestedObject2": "something else" - } -} -placeholderDoc = { - "blib":"blub", - "public": False -} - -with OpenSearchContainer(port_to_expose=9200) as opensearch: - client = opensearch.get_client() - creation_result = client.index(index="database", body=doc1) - creation_result = client.index(index="database", body=doc2) - creation_result = client.index(index="database", body=doc3) - creation_result = client.index(index="user", body=placeholderDoc) - creation_result = client.index(index="table", body=placeholderDoc) - creation_result = client.index(index="column", body=placeholderDoc) - creation_result = client.index(index="identifier", body=placeholderDoc) - refresh_result = client.indices.refresh(index="database") - search_result = client.search(index="database", body={"query": {"match_all": {}}}) - pp = pprint.PrettyPrinter(indent=1) - config = opensearch.get_config() - os.environ["TEST_OPENSEARCH_HOST"] = config["host"] - os.putenv("TEST_OPENSEARCH_HOST", config["host"]) - os.environ["TEST_OPENSEARCH_PORT"] = config["port"] - os.environ["TEST_OPENSEARCH_USERNAME"] = config["user"] - os.environ["TEST_OPENSEARCH_PASSWORD"] = config["password"] - - pickle_info = {} - pickle_info["port"] = config["port"] - pickle_info["host"] = config["host"] - with open(".testpickle", "ab") as outfile: - pickle.dump(pickle_info, outfile) - print(f"serving on port: {config['port']}") - while True: - time.sleep(1) - diff --git a/dbrepo-search-service/test/test_app.py b/dbrepo-search-service/test/test_app.py new file mode 100644 index 0000000000000000000000000000000000000000..1b1af020987175fcd8894e61fd2e85519f42c998 --- /dev/null +++ b/dbrepo-search-service/test/test_app.py @@ -0,0 +1,300 @@ +import json +import time +import unittest +import datetime + +import jwt +from dbrepo.api.dto import Database, User, UserAttributes, Container, Image, Table, Constraints, Column, ColumnType, \ + Concept, Unit + +from app import app + +req = Database(id=1, + name="Test", + internal_name="test_tuw1", + creator=User(id="c6b71ef5-2d2f-48b2-9d79-b8f23a3a0502", + username="foo", + attributes=UserAttributes(theme="dark")), + owner=User(id="c6b71ef5-2d2f-48b2-9d79-b8f23a3a0502", + username="foo", + attributes=UserAttributes(theme="dark")), + contact=User(id="c6b71ef5-2d2f-48b2-9d79-b8f23a3a0502", + username="foo", + attributes=UserAttributes(theme="dark")), + created=datetime.datetime(2024, 3, 25, 16, tzinfo=datetime.timezone.utc), + exchange_name="dbrepo", + is_public=True, + container=Container(id=1, + name="MariaDB", + internal_name="mariadb", + host="data-db", + port="3306", + created=datetime.datetime(2024, 3, 1, 10, tzinfo=datetime.timezone.utc), + sidecar_host="data-db-sidecar", + sidecar_port=3305, + image=Image(id=1, + registry="docker.io", + name="mariadb", + version="11.1.3", + dialect="org.hibernate.dialect.MariaDBDialect", + driver_class="org.mariadb.jdbc.Driver", + jdbc_method="mariadb", + default_port=3306)), + tables=[Table(id=1, database_id=1, name="Data", internal_name="data", + creator=User(id="c6b71ef5-2d2f-48b2-9d79-b8f23a3a0502", + username="foo", + attributes=UserAttributes(theme="dark")), + owner=User(id="c6b71ef5-2d2f-48b2-9d79-b8f23a3a0502", + username="foo", + attributes=UserAttributes(theme="dark")), + created=datetime.datetime(2024, 3, 1, 10, tzinfo=datetime.timezone.utc), + constraints=Constraints(uniques=[], foreign_keys=[], checks=[], primary_key=[]), + is_versioned=False, + created_by="c6b71ef5-2d2f-48b2-9d79-b8f23a3a0502", + queue_name="dbrepo", + routing_key="dbrepo.1.1", + is_public=True, + columns=[Column(id=1, database_id=1, table_id=1, name="ID", internal_name="id", + column_type=ColumnType.BIGINT, is_public=True, is_null_allowed=False, + size=20, d=0, + concept=Concept(id=1, uri="http://www.wikidata.org/entity/Q2221906", + created=datetime.datetime(2024, 3, 1, 10, + tzinfo=datetime.timezone.utc)), + unit=Unit(id=1, + uri="http://www.ontology-of-units-of-measure.org/resource/om-2/degreeCelsius", + created=datetime.datetime(2024, 3, 1, 10, + tzinfo=datetime.timezone.utc)), + val_min=0, + val_max=10)] + )]) + + +class JwtTest(unittest.TestCase): + + def token(self, roles: [str], iat: int = int(time.time())): + claims = { + 'iat': iat, + 'realm_access': { + 'roles': roles + } + } + with open('test/rsa/rs256.key', 'rb') as fh: + return jwt.JWT().encode(claims, jwt.jwk_from_pem(fh.read()), alg='RS256') + + def test_update_database_media_type_fails(self): + with app.test_client() as test_client: + # test + response = test_client.put('/api/search/database/1', + headers={'Authorization': f'Bearer {self.token(["update-search-index"])}'}) + self.assertEqual(415, response.status_code) + + def test_health_succeeds(self): + with app.test_client() as test_client: + # test + response = test_client.get('/health') + self.assertEqual(200, response.status_code) + + def test_update_database_no_auth_fails(self): + with app.test_client() as test_client: + # test + response = test_client.put('/api/search/database/1') + self.assertEqual(401, response.status_code) + + def test_update_database_no_body_fails(self): + with app.test_client() as test_client: + # test + response = test_client.put('/api/search/database/1', + headers={'Authorization': f'Bearer {self.token(["update-search-index"])}', + 'Content-Type': 'application/json'}) + self.assertEqual(400, response.status_code) + + def test_update_database_empty_body_fails(self): + with app.test_client() as test_client: + # test + response = test_client.put('/api/search/database/1', + headers={'Authorization': f'Bearer {self.token(["update-search-index"])}', + 'Content-Type': 'application/json'}, + data={}) + self.assertEqual(400, response.status_code) + + def test_update_database_malformed_body_fails(self): + with app.test_client() as test_client: + # test + response = test_client.put('/api/search/database/1', + headers={'Authorization': f'Bearer {self.token(["update-search-index"])}', + 'Content-Type': 'application/json'}, + data=dict({"id": 1})) + self.assertEqual(400, response.status_code) + + def test_update_database_succeeds(self): + with app.test_client() as test_client: + # test + response = test_client.put('/api/search/database/1', + headers={'Authorization': f'Bearer {self.token(["update-search-index"])}', + 'Content-Type': 'application/json'}, + data=req.model_dump_json()) + self.assertEqual(202, response.status_code) + + def test_get_fields_succeeds(self): + with app.test_client() as test_client: + # test + response = test_client.get('/api/search/database/fields', headers={'Content-Type': 'application/json'}) + self.assertEqual(200, response.status_code) + + def test_get_fields_fails(self): + with app.test_client() as test_client: + # test + response = test_client.get('/api/search/unknown/fields', headers={'Content-Type': 'application/json'}) + self.assertEqual(404, response.status_code) + + def test_delete_database_no_auth_fails(self): + with app.test_client() as test_client: + # test + response = test_client.delete('/api/search/database/1') + self.assertEqual(401, response.status_code) + + def test_delete_database_no_role_fails(self): + with app.test_client() as test_client: + # test + response = test_client.delete('/api/search/database/1', + headers={'Authorization': f'Bearer {self.token([])}'}) + self.assertEqual(403, response.status_code) + + def test_delete_database_succeeds(self): + with app.test_client() as test_client: + # mock + test_client.put('/api/search/database/1', + headers={'Authorization': f'Bearer {self.token(["update-search-index"])}', + 'Content-Type': 'application/json'}, + data=req.model_dump_json()) + # test + response = test_client.delete('/api/search/database/1', + headers={'Authorization': f'Bearer {self.token(["admin"])}'}) + self.assertEqual(202, response.status_code) + + def test_delete_database_not_found_fails(self): + with app.test_client() as test_client: + # test + response = test_client.delete('/api/search/database/1', + headers={'Authorization': f'Bearer {self.token(["admin"])}'}) + self.assertEqual(404, response.status_code) + + def test_get_fuzzy_search_succeeds(self): + with app.test_client() as test_client: + # test + response = test_client.get('/api/search?q=test') + self.assertEqual(200, response.status_code) + + def test_get_fuzzy_search_no_query_fails(self): + with app.test_client() as test_client: + # test + response = test_client.get('/api/search') + self.assertEqual(400, response.status_code) + + def test_get_index_succeeds(self): + with app.test_client() as test_client: + # test + response = test_client.get('/api/search/table') + self.assertEqual(200, response.status_code) + + def test_get_index_fails(self): + with app.test_client() as test_client: + # test + response = test_client.get('/api/search/unknown') + self.assertEqual(404, response.status_code) + + def test_post_general_search_media_type_fails(self): + with app.test_client() as test_client: + # test + response = test_client.post('/api/search/database') + self.assertEqual(415, response.status_code) + + def test_post_general_search_no_body_fails(self): + with app.test_client() as test_client: + # test + response = test_client.post('/api/search/database', headers={'Content-Type': 'application/json'}) + self.assertEqual(400, response.status_code) + + def test_post_general_search_succeeds(self): + with app.test_client() as test_client: + # mock + test_client.put('/api/search/database/1', + headers={'Authorization': f'Bearer {self.token(["update-search-index"])}', + 'Content-Type': 'application/json'}, + data=req.model_dump_json()) + # test + response = test_client.post('/api/search/database', headers={'Content-Type': 'application/json'}, + data=json.dumps({'id': 1})) + self.assertEqual(200, response.status_code) + + def test_post_general_search_table_succeeds(self): + with app.test_client() as test_client: + # mock + test_client.put('/api/search/database/1', + headers={'Authorization': f'Bearer {self.token(["update-search-index"])}', + 'Content-Type': 'application/json'}, + data=req.model_dump_json()) + # test + response = test_client.post('/api/search/table', headers={'Content-Type': 'application/json'}, + data=json.dumps({'id': 1})) + self.assertEqual(200, response.status_code) + + def test_post_general_search_column_succeeds(self): + with app.test_client() as test_client: + # mock + test_client.put('/api/search/database/1', + headers={'Authorization': f'Bearer {self.token(["update-search-index"])}', + 'Content-Type': 'application/json'}, + data=req.model_dump_json()) + # test + response = test_client.post('/api/search/column', headers={'Content-Type': 'application/json'}, + data=json.dumps({'id': 1})) + self.assertEqual(200, response.status_code) + + def test_post_general_search_identifier_succeeds(self): + with app.test_client() as test_client: + # mock + test_client.put('/api/search/database/1', + headers={'Authorization': f'Bearer {self.token(["update-search-index"])}', + 'Content-Type': 'application/json'}, + data=req.model_dump_json()) + # test + response = test_client.post('/api/search/identifier', headers={'Content-Type': 'application/json'}, + data=json.dumps({'id': 1})) + self.assertEqual(200, response.status_code) + + def test_post_general_search_concept_succeeds(self): + with app.test_client() as test_client: + # mock + test_client.put('/api/search/database/1', + headers={'Authorization': f'Bearer {self.token(["update-search-index"])}', + 'Content-Type': 'application/json'}, + data=req.model_dump_json()) + # test + response = test_client.post('/api/search/concept', headers={'Content-Type': 'application/json'}, + data=json.dumps({'id': 1})) + self.assertEqual(200, response.status_code) + + def test_post_general_search_unit_succeeds(self): + with app.test_client() as test_client: + # mock + test_client.put('/api/search/database/1', + headers={'Authorization': f'Bearer {self.token(["update-search-index"])}', + 'Content-Type': 'application/json'}, + data=req.model_dump_json()) + # test + response = test_client.post('/api/search/unit', headers={'Content-Type': 'application/json'}, + data=json.dumps({'id': 1})) + self.assertEqual(200, response.status_code) + + def test_post_general_search_view_succeeds(self): + with app.test_client() as test_client: + # mock + test_client.put('/api/search/database/1', + headers={'Authorization': f'Bearer {self.token(["update-search-index"])}', + 'Content-Type': 'application/json'}, + data=req.model_dump_json()) + # test + response = test_client.post('/api/search/view', headers={'Content-Type': 'application/json'}, + data=json.dumps({'id': 1})) + self.assertEqual(200, response.status_code) diff --git a/dbrepo-search-service/test/test_jwt.py b/dbrepo-search-service/test/test_jwt.py new file mode 100644 index 0000000000000000000000000000000000000000..59cd4ee1168117d0aeb6bf3549fe5088edc379b9 --- /dev/null +++ b/dbrepo-search-service/test/test_jwt.py @@ -0,0 +1,97 @@ +import time +import unittest + +import jwt +import requests_mock + +from app import verify_token, app, verify_password, get_user_roles +from clients.keycloak_client import User + + +class JwtTest(unittest.TestCase): + + def response(self, roles: [str]) -> dict: + return dict({ + "client_id": "username", + "realm_access": { + "roles": roles + } + }) + + def token(self, roles: [str], iat: int = int(time.time())) -> str: + claims = { + 'iat': iat, + 'realm_access': { + 'roles': roles + } + } + with open('test/rsa/rs256.key', 'rb') as fh: + return jwt.JWT().encode(claims, jwt.jwk_from_pem(fh.read()), alg='RS256') + + def test_verify_token_no_token_fails(self): + with app.app_context(): + # test + user = verify_token(None) + self.assertFalse(user) + + def test_verify_token_empty_token_fails(self): + with app.app_context(): + # test + user = verify_token("") + self.assertFalse(user) + + def test_verify_token_malformed_token_fails(self): + with app.app_context(): + # test + user = verify_token("eyEYEY12345") + self.assertFalse(user) + + def test_verify_token_succeeds(self): + with app.app_context(): + with requests_mock.Mocker() as mock: + # mock + mock.post('http://auth-service:8080/api/auth/realms/dbrepo/protocol/openid-connect/token', + json=self.response([])) + # test + user = verify_token(self.token([])) + self.assertEqual([], user.roles) + + def test_verify_password_no_username_fails(self): + with app.app_context(): + # test + user = verify_password(None, "pass") + self.assertFalse(user) + + def test_verify_password_empty_username_fails(self): + with app.app_context(): + # test + user = verify_password("", "pass") + self.assertFalse(user) + + def test_verify_password_no_password_fails(self): + with app.app_context(): + # test + user = verify_password("username", None) + self.assertFalse(user) + + def test_verify_password_empty_password_fails(self): + with app.app_context(): + # test + user = verify_password("username", "") + self.assertFalse(user) + + def test_verify_password_succeeds(self): + with app.app_context(): + with requests_mock.Mocker() as mock: + # mock + mock.post('http://auth-service:8080/api/auth/realms/dbrepo/protocol/openid-connect/token', + json=self.response([])) + # test + user = verify_password("username", "password") + self.assertIsNotNone(user) + + def test_get_user_roles_succeeds(self): + with app.app_context(): + # test + roles: [str] = get_user_roles(User(username="username", roles=[])) + self.assertEqual([], roles) diff --git a/dbrepo-search-service/test/test_keycloak_client.py b/dbrepo-search-service/test/test_keycloak_client.py new file mode 100644 index 0000000000000000000000000000000000000000..453a9b802be9885daa8e87afe265c272ee1ca211 --- /dev/null +++ b/dbrepo-search-service/test/test_keycloak_client.py @@ -0,0 +1,57 @@ +import time +import unittest + +import jwt +import requests_mock + +from app import app +from clients.keycloak_client import KeycloakClient + + +class JwtTest(unittest.TestCase): + + def response(self, username) -> dict: + return dict({ + "client_id": username, + "access_token": "eyEY1234" + }) + + def token(self, username: str, roles: [str], iat: int = int(time.time())) -> str: + claims = { + 'iat': iat, + 'client_id': username, + 'realm_access': { + 'roles': roles + } + } + with open('test/rsa/rs256.key', 'rb') as fh: + return jwt.JWT().encode(claims, jwt.jwk_from_pem(fh.read()), alg='RS256') + + def test_obtain_user_token_succeeds(self): + with app.app_context(): + with requests_mock.Mocker() as mock: + # mock + mock.post('http://auth-service:8080/api/auth/realms/dbrepo/protocol/openid-connect/token', + json=self.response("username")) + # test + token = KeycloakClient().obtain_user_token("username", "password") + self.assertEqual("eyEY1234", token) + + def test_obtain_user_token_malformed_fails(self): + with app.app_context(): + with requests_mock.Mocker() as mock: + # mock + mock.post('http://auth-service:8080/api/auth/realms/dbrepo/protocol/openid-connect/token', + json={"client_id": "username"}) + # test + try: + KeycloakClient().obtain_user_token("username", "password") + self.fail() + except AssertionError: + pass + + def test_verify_jwt_succeeds(self): + with app.app_context(): + # test + user = KeycloakClient().verify_jwt(self.token("username", [])) + self.assertEqual("username", user.username) diff --git a/dbrepo-search-service/test/test_opensearch_client.py b/dbrepo-search-service/test/test_opensearch_client.py index 2bab038128fa7dd201dfcca81240f906358e37eb..581e5f8c5d94435c4344b4e8478ec09b116fd735 100644 --- a/dbrepo-search-service/test/test_opensearch_client.py +++ b/dbrepo-search-service/test/test_opensearch_client.py @@ -4,10 +4,11 @@ import unittest import opensearchpy from dbrepo.api.dto import Database, User, UserAttributes, Container, Image, Table, Column, ColumnType, Constraints, \ PrimaryKey, TableMinimal, ColumnMinimal, Concept, Unit +from opensearchpy import NotFoundError from app import app -from clients.opensearch_client import OpenSearchClient +from init.clients.opensearch_client import OpenSearchClient req = Database(id=1, name="Test", @@ -55,8 +56,8 @@ req = Database(id=1, routing_key="dbrepo.1.1", is_public=True, columns=[Column(id=1, database_id=1, table_id=1, name="ID", internal_name="id", - auto_generated=True, column_type=ColumnType.BIGINT, is_public=True, - is_null_allowed=False, size=20, d=0, + column_type=ColumnType.BIGINT, is_public=True, is_null_allowed=False, + size=20, d=0, concept=Concept(id=1, uri="http://www.wikidata.org/entity/Q2221906", created=datetime.datetime(2024, 3, 1, 10, tzinfo=datetime.timezone.utc)), @@ -73,9 +74,8 @@ class OpenSearchClientTest(unittest.TestCase): def test_update_database_succeeds(self): with app.app_context(): - client = OpenSearchClient() # mock - client.update_database(database_id=1, data=req) + OpenSearchClient().update_database(database_id=req.id, data=req) # test req.tables = [Table(id=1, @@ -87,9 +87,10 @@ class OpenSearchClientTest(unittest.TestCase): database_id=req.id, constraints=Constraints(uniques=[], foreign_keys=[], checks=[], primary_key=[PrimaryKey(id=1, - table=TableMinimal(id=1, database_id=1), + table=TableMinimal(id=1, + database_id=req.id), column=ColumnMinimal(id=1, table_id=1, - database_id=1))]), + database_id=req.id))]), is_versioned=True, created_by="c6b71ef5-2d2f-48b2-9d79-b8f23a3a0502", creator=User(id="c6b71ef5-2d2f-48b2-9d79-b8f23a3a0502", @@ -104,11 +105,10 @@ class OpenSearchClientTest(unittest.TestCase): internal_name="id", database_id=req.id, table_id=1, - auto_generated=True, column_type=ColumnType.BIGINT, is_public=True, is_null_allowed=False)])] - database = client.update_database(database_id=1, data=req) + database = OpenSearchClient().update_database(database_id=req.id, data=req) self.assertEqual(1, database.id) self.assertEqual("Test", database.name) self.assertEqual("test_tuw1", database.internal_name) @@ -153,16 +153,13 @@ class OpenSearchClientTest(unittest.TestCase): self.assertEqual(ColumnType.BIGINT, database.tables[0].columns[0].column_type) self.assertEqual(1, database.tables[0].columns[0].database_id) self.assertEqual(1, database.tables[0].columns[0].table_id) - self.assertEqual(True, database.tables[0].columns[0].auto_generated) self.assertEqual(True, database.tables[0].columns[0].is_public) self.assertEqual(False, database.tables[0].columns[0].is_null_allowed) def test_update_database_create_succeeds(self): with app.app_context(): - client = OpenSearchClient() - # test - database = client.update_database(database_id=1, data=req) + database = OpenSearchClient().update_database(database_id=req.id, data=req) self.assertEqual(1, database.id) self.assertEqual("Test", database.name) self.assertEqual("test_tuw1", database.internal_name) @@ -187,125 +184,87 @@ class OpenSearchClientTest(unittest.TestCase): def test_update_database_malformed_fails(self): with app.app_context(): app.config['OPENSEARCH_USERNAME'] = 'i_do_not_exist' - client = OpenSearchClient() # test try: - database = client.update_database(database_id=1, data=req) + database = OpenSearchClient().update_database(database_id=req.id, data=req) except opensearchpy.exceptions.TransportError: pass def test_delete_database_fails(self): with app.app_context(): - client = OpenSearchClient() # test try: - client.delete_database(database_id=9999) + OpenSearchClient().delete_database(database_id=9999) except opensearchpy.exceptions.NotFoundError: pass def test_delete_database_succeeds(self): with app.app_context(): - client = OpenSearchClient() - # mock - client.update_database(database_id=req.id, data=req) + OpenSearchClient().update_database(database_id=req.id, data=req) # test - client.delete_database(database_id=req.id) + OpenSearchClient().delete_database(database_id=req.id) - def test_find_database_succeeds(self): + def test_get_database_succeeds(self): with app.app_context(): - client = OpenSearchClient() - # mock - client.update_database(database_id=req.id, data=req) + OpenSearchClient().update_database(database_id=req.id, data=req) # test - client.get_database(database_id=req.id) + database = OpenSearchClient().get_database(database_id=req.id) + self.assertEqual(req.id, database.id) - def test_find_database_fails(self): + def test_get_database_fails(self): with app.app_context(): - client = OpenSearchClient() # mock - client.update_database(database_id=1, data=req) + OpenSearchClient().update_database(database_id=req.id, data=req) # test try: - client.get_database(database_id=1) + OpenSearchClient().get_database(database_id=req.id) except opensearchpy.exceptions.NotFoundError: pass - # def test_query_index_by_term_opensearch_contains_succeeds(self): - # with app.app_context(): - # client = OpenSearchClient() - # - # # mock - # client.update_database(database_id=1, data=req) - # - # # test - # response = client.query_index_by_term_opensearch(term="test", mode="contains") - # self.assertEqual(1, len(response)) - # self.assertEqual(1, response[0]['id']) - # self.assertEqual('Test', response[0]['name']) - - # def test_query_index_by_term_opensearch_exact_succeeds(self): - # with app.app_context(): - # client = OpenSearchClient() - # - # # mock - # client.update_database(database_id=1, data=req) - # - # # test - # response = client.query_index_by_term_opensearch(term="test", mode="exact") - # self.assertEqual(1, len(response)) - # self.assertEqual(1, response[0]['id']) - # self.assertEqual('Test', response[0]['name']) - def test_get_fields_for_index_database_succeeds(self): with app.app_context(): - client = OpenSearchClient() - # mock - client.update_database(database_id=1, data=req) + OpenSearchClient().update_database(database_id=req.id, data=req) # test - response = client.get_fields_for_index(type="database") + response = OpenSearchClient().get_fields_for_index(field_type="database") self.assertTrue(len(response) > 0) def test_get_fields_for_index_user_succeeds(self): with app.app_context(): - client = OpenSearchClient() - # mock - client.update_database(database_id=1, data=req) + OpenSearchClient().update_database(database_id=req.id, data=req) # test - response = client.get_fields_for_index(type="user") + response = OpenSearchClient().get_fields_for_index(field_type="user") self.assertTrue(len(response) > 0) def test_fuzzy_search_succeeds(self): with app.app_context(): - client = OpenSearchClient() - # mock - client.update_database(database_id=1, data=req) + OpenSearchClient().update_database(database_id=req.id, data=req) # test - response = client.fuzzy_search(search_term="test") + response = OpenSearchClient().fuzzy_search(search_term="test") self.assertTrue(len(response) > 0) - # def test_general_search_succeeds(self): - # with app.app_context(): - # client = OpenSearchClient() - # - # # mock - # client.update_database(database_id=1, data=req) - # - # # test - # response = client.general_search(type="database", field_value_pairs={"name": "Test", - # "id": None}) - # self.assertTrue(len(response) > 0) + def test_unit_independent_search_fails(self): + with app.app_context(): + # mock + OpenSearchClient().update_database(database_id=req.id, data=req) + # test + try: + OpenSearchClient().unit_independent_search(0, 100, { + "unit.uri": "http://www.ontology-of-units-of-measure.org/resource/om-2/degreeCelsius"}) + self.fail() + except NotFoundError: + pass diff --git a/dbrepo-storage-service/README.md b/dbrepo-storage-service/README.md new file mode 100644 index 0000000000000000000000000000000000000000..b38fa4ac60840143df2aed35c592d8cec0329b33 --- /dev/null +++ b/dbrepo-storage-service/README.md @@ -0,0 +1,11 @@ +# Storage Service + +Based on [SeaweedFS](https://github.com/seaweedfs/seaweedfs). + +### Endpoints + +#### Filer + +Upload files and inspect the S3-buckets. + +- Filer: http://localhost:8888 diff --git a/dbrepo-ui/Dockerfile b/dbrepo-ui/Dockerfile index 4c69be4d1ae04188dd3b167f277cdd85702151a9..c2f527b9dddfc10220d9d3ca6001c0f5101b2638 100644 --- a/dbrepo-ui/Dockerfile +++ b/dbrepo-ui/Dockerfile @@ -1,7 +1,8 @@ -FROM oven/bun:1.0.26-alpine AS build +FROM oven/bun:1.1.20-alpine AS build WORKDIR /app +COPY ./bun.lockb ./bun.lockb COPY ./package.json ./package.json RUN bun install @@ -25,11 +26,13 @@ COPY ./nuxt.config.ts ./nuxt.config.ts RUN bun run build -FROM oven/bun:1.0.26-alpine AS runtime +FROM node:22.9.0-alpine3.20 AS runtime ARG APP_VERSION="latest" ARG COMMIT="" +RUN apk add --no-cache curl bash + USER 1000 WORKDIR /app @@ -43,4 +46,4 @@ ENV NUXT_PUBLIC_COMMIT="${COMMIT:-}" EXPOSE 3000 -ENTRYPOINT [ "bun", "run", ".output/server/index.mjs" ] +ENTRYPOINT [ "node", ".output/server/index.mjs" ] diff --git a/dbrepo-ui/assets/globals.css b/dbrepo-ui/assets/globals.css index 8f791a9edd2b82244332b41587708c3197f1d1b3..52da2e48c8c2e7589ddcbce27fe67520acd74763 100644 --- a/dbrepo-ui/assets/globals.css +++ b/dbrepo-ui/assets/globals.css @@ -1,4 +1,13 @@ a { color: var(--v-theme-primary); } +label.native, +select.native { + display: block; } + +select.native { + -webkit-appearance: listbox; + border-style: solid; + width: 100%; } + /*# sourceMappingURL=globals.css.map */ diff --git a/dbrepo-ui/assets/globals.css.map b/dbrepo-ui/assets/globals.css.map index b9c0623a76d6530341406b9f715d4dea45c77046..6f271c8f99f4295e8438524dea16b6a48b253635 100644 --- a/dbrepo-ui/assets/globals.css.map +++ b/dbrepo-ui/assets/globals.css.map @@ -1,6 +1,6 @@ { "version": 3, -"mappings": "AAAA,CAAE;EACA,KAAK,EAAE,sBAAsB", +"mappings": "AAAA,CAAE;EACA,KAAK,EAAE,sBAAsB;;AAG/B;aACc;EACZ,OAAO,EAAE,KAAK;;AAGhB,aAAc;EACZ,kBAAkB,EAAE,OAAO;EAC3B,YAAY,EAAE,KAAK;EACnB,KAAK,EAAE,IAAI", "sources": ["globals.scss"], "names": [], "file": "globals.css" diff --git a/dbrepo-ui/assets/globals.scss b/dbrepo-ui/assets/globals.scss index 6b6b26ac202cdfae8c6783d7a8f5c31116e98697..5d4d4e06a7cdcde8e801cccd14c0eb2f07c0824d 100644 --- a/dbrepo-ui/assets/globals.scss +++ b/dbrepo-ui/assets/globals.scss @@ -1,3 +1,14 @@ a { color: var(--v-theme-primary); } + +label.native, +select.native { + display: block; +} + +select.native { + -webkit-appearance: listbox; + border-style: solid; + width: 100%; +} diff --git a/dbrepo-ui/bun.lockb b/dbrepo-ui/bun.lockb index e258f022c401afbdd44115c2215ac794e28920dd..3f85eb8de9c7a334e2a6a89d3cbcf75254751610 100755 Binary files a/dbrepo-ui/bun.lockb and b/dbrepo-ui/bun.lockb differ diff --git a/dbrepo-ui/components/OntologiesList.vue b/dbrepo-ui/components/OntologiesList.vue index c3ffd3994541bf29dfa7c3f091d6089760624f86..44f0eddc3f4c8b3542cd1b7f237cac05603c6375 100644 --- a/dbrepo-ui/components/OntologiesList.vue +++ b/dbrepo-ui/components/OntologiesList.vue @@ -8,10 +8,12 @@ rounded="0"> <v-divider class="mx-4" /> - <v-card-title - v-text="ontology.prefix" /> - <v-card-subtitle - v-text="ontology.uri" /> + <v-card-title> + {{ ontology.prefix }} + </v-card-title> + <v-card-subtitle> + {{ ontology.uri }} + </v-card-subtitle> <v-card-text> <div class="db-tags"> diff --git a/dbrepo-ui/components/container/ContainerCard.vue b/dbrepo-ui/components/container/ContainerCard.vue new file mode 100644 index 0000000000000000000000000000000000000000..ed1479f64d3ad8043968e03edbfcd940190e3fb6 --- /dev/null +++ b/dbrepo-ui/components/container/ContainerCard.vue @@ -0,0 +1,56 @@ +<template> + <v-card + v-if="container" + variant="flat" + rounded="0"> + <v-divider class="mx-4" /> + <v-card-title> + {{ container.name }} + </v-card-title> + <v-card-subtitle> + {{ $t('pages.container.subtitle.text') }} + </v-card-subtitle> + <v-card-text> + <v-progress-linear + v-model="utilization" + :color="colorVariant" + height="20" + class="font-small"> + <template v-slot:default> + {{ container.count }} / {{ container.quota }} + </template> + </v-progress-linear> + </v-card-text> + </v-card> +</template> + +<script> +export default { + data() { + return { + loading: false + } + }, + props: { + container: { + default: () => { + return null + } + } + }, + computed: { + utilization () { + return this.container.count * 100.0 / this.container.quota + }, + colorVariant () { + return this.isContrastTheme ? '' : (this.isDarkTheme ? 'tertiary' : 'secondary') + }, + isContrastTheme () { + return this.$vuetify.theme.global.name.toLowerCase().endsWith('contrast') + }, + isDarkTheme () { + return this.$vuetify.theme.global.name.toLowerCase().startsWith('dark') + } + } +} +</script> diff --git a/dbrepo-ui/components/container/ContainerList.vue b/dbrepo-ui/components/container/ContainerList.vue new file mode 100644 index 0000000000000000000000000000000000000000..567ee4eec4fdb361157a8dd8d7d0d3e0f6e77d7b --- /dev/null +++ b/dbrepo-ui/components/container/ContainerList.vue @@ -0,0 +1,42 @@ +<template> + <div> + <v-card + variant="flat" + rounded="0"> + <v-list-item + v-if="loading" + lines="two"> + <Loading /> + </v-list-item> + </v-card> + <ContainerCard + v-for="(container, idx) in containers" + :container="container" + :key="idx"/> + </div> +</template> + +<script> +import ContainerCard from '@/components/container/ContainerCard.vue' + +export default { + components: { + ContainerCard + }, + props: { + containers: { + type: Array, + default: () => { + return [] + } + }, + loading: { + type: Boolean, + default: () => { + return true + } + } + } +} +</script> + diff --git a/dbrepo-ui/components/database/DatabaseCard.vue b/dbrepo-ui/components/database/DatabaseCard.vue index 48aefa7493ce5beb52d8ec62cf794d64368b8489..fba3853a31cf25649f915d4c0a3e422f5ec879bf 100644 --- a/dbrepo-ui/components/database/DatabaseCard.vue +++ b/dbrepo-ui/components/database/DatabaseCard.vue @@ -9,8 +9,9 @@ <v-divider class="mx-4" /> <v-card-title> <span - class="text-primary text-decoration-underline" - v-text="formatTitle(database)" /> + class="text-primary text-decoration-underline"> + {{ formatTitle(database) }} + </span> <v-progress-circular v-if="loading" color="primary" @@ -18,56 +19,66 @@ class="ml-1" indeterminate /> </v-card-title> - <v-card-subtitle - v-text="formatCreators(database)" /> + <v-card-subtitle> + {{ formatCreators(database) }} + </v-card-subtitle> <v-card-text> - <div v-text="identifierDescription(database)" /> + <div> + {{ identifierDescription(database) }} + </div> <div class="mt-2 db-tags"> <v-chip v-if="database.is_public" size="small" color="success" - :text="$t('toolbars.database.public')" - variant="outlined" /> + variant="outlined"> + {{ $t('toolbars.database.public') }} + </v-chip> <v-chip v-if="!database.is_public" size="small" :color="colorVariant" variant="outlined" - :text="$t('toolbars.database.private')" - flat /> + flat> + {{ $t('toolbars.database.private') }} + </v-chip> <v-chip v-if="identifierYear(database)" size="small" :color="colorVariant" - variant="outlined" - v-text="identifierYear(database)" /> + variant="outlined"> + {{ identifierYear(database) }} + </v-chip> <v-chip v-if="identifier(database)" size="small" :color="colorVariant" - variant="outlined" - v-text="identifierPublisher(database)" /> + variant="outlined"> + {{ identifierPublisher(database) }} + </v-chip> <v-chip v-for="(license, i) in identifierLicenses(database)" :key="`l-${i}`" size="small" color="success" - variant="outlined" - v-text="license.identifier" /> + variant="outlined"> + {{ license.identifier }} + </v-chip> <v-chip v-for="(funder, i) in identifierFunders(database)" :key="`f-${i}`" size="small" :color="colorVariant" - variant="outlined" - v-text="funder.funder_name" /> + variant="outlined"> + {{ funder.funder_name }} + </v-chip> <v-chip v-if="identifierLanguage(database)" size="small" :color="colorVariant" - variant="outlined" - v-text="identifierLanguage(database)" /> + variant="outlined"> + {{ identifierLanguage(database) }} + </v-chip> </div> </v-card-text> </v-card> diff --git a/dbrepo-ui/components/database/DatabaseCreate.vue b/dbrepo-ui/components/database/DatabaseCreate.vue index 275b7198311f6edc62aeefb07311e2d01fea771c..5da87cebbda9731ae842636654a40ce6fdea14a8 100644 --- a/dbrepo-ui/components/database/DatabaseCreate.vue +++ b/dbrepo-ui/components/database/DatabaseCreate.vue @@ -6,9 +6,13 @@ autocomplete="off" @submit.prevent="submit"> <v-card - variant="elevated" - :title="$t('pages.database.subpages.create.title')" - :subtitle="$t('pages.database.subpages.create.subtitle')"> + variant="elevated"> + <v-card-title> + {{ $t('pages.database.subpages.create.title') }} + </v-card-title> + <v-card-subtitle> + {{ $t('pages.database.subpages.create.subtitle') }} + </v-card-subtitle> <v-card-text> <v-row dense> <v-col> @@ -40,7 +44,17 @@ item-value="id" :rules="[v => !!v || $t('validation.required')]" return-object - required /> + required> + <template + v-slot:selection> + <span>{{ engine.name }}</span> + </template> + <template + v-if="engine" + v-slot:details> + {{ $t('pages.database.subpages.create.utilization.label') }} {{ engine.count }}/{{ engine.quota }} + </template> + </v-select> </v-col> </v-row> </v-card-text> @@ -48,16 +62,18 @@ <v-spacer /> <v-btn :variant="buttonVariant" - :text="$t('navigation.cancel')" - @click="cancel" /> + @click="cancel"> + {{ $t('navigation.cancel') }} + </v-btn> <v-btn :disabled="!valid || loading" color="primary" type="submit" variant="flat" - :text="$t('pages.database.subpages.create.submit.text')" :loading="loading" - @click="create" /> + @click="create"> + {{ $t('pages.database.subpages.create.submit.text') }} + </v-btn> </v-card-actions> </v-card> </v-form> @@ -106,7 +122,13 @@ export default { this.loadingContainers = true containerService.findAll() .then((containers) => { - this.engines = containers + const freeContainers = containers.filter(c => c.count < c.quota) + const defaultContainers = freeContainers.filter(c => c.image.default) + defaultContainers.sort(this.compareContainerUtilization) + this.engines = defaultContainers + const other = freeContainers.filter(c => !c.image.default) + other.sort(this.compareContainerUtilization) + other.forEach(c => this.engines.push(c)) if (this.engines.length > 0) { this.engine = this.engines[0] } @@ -139,6 +161,9 @@ export default { toast.error(this.$t(code)) }) }, + compareContainerUtilization (container, other) { + return Math.round(container.count / container.quota) < Math.round(other.count / other.quota) + }, notEmpty } } diff --git a/dbrepo-ui/components/database/DatabaseToolbar.vue b/dbrepo-ui/components/database/DatabaseToolbar.vue index 0c87e5599c688b3c4feebfbadb09a8868071d54d..5f3c8c83989bd20fa67f6f327fdc9676767acbb4 100644 --- a/dbrepo-ui/components/database/DatabaseToolbar.vue +++ b/dbrepo-ui/components/database/DatabaseToolbar.vue @@ -8,8 +8,9 @@ type="subtitle" width="200" /> <span - v-if="database && $vuetify.display.lgAndUp" - v-text="database.name" /> + v-if="database && $vuetify.display.lgAndUp"> + {{ database.name }} + </span> <v-chip v-if="database && database.is_public" size="small" @@ -135,6 +136,12 @@ export default { } return this.access.type === 'write_all' || this.access.type === 'write_own' }, + hasReadAccess () { + if (!this.access) { + return false + } + return this.access.type === 'read' || this.access.type === 'write_all' || this.access.type === 'write_own' + }, canImportCsv () { if (!this.user || !this.hasWriteAccess) { return false @@ -142,10 +149,13 @@ export default { return this.roles.includes('insert-table-data') }, canCreateSubset () { - if (!this.user) { + if (!this.database) { return false } - return this.roles.includes('execute-query') + if (this.database.is_public) { + return true + } + return this.hasReadAccess }, canCreateView () { if (!this.user || !this.isOwner) { diff --git a/dbrepo-ui/components/dialogs/DropTable.vue b/dbrepo-ui/components/dialogs/DropTable.vue index 1f62735de5e6ce549386894f525074f53d5cdd5a..d465c882d0529a817be21f836ea82739fc30155b 100644 --- a/dbrepo-ui/components/dialogs/DropTable.vue +++ b/dbrepo-ui/components/dialogs/DropTable.vue @@ -7,9 +7,13 @@ <v-card-text> <v-row dense> <v-col> - <span v-text="$t('pages.table.subpages.drop.warning.prefix')" /> + <span> + {{ $t('pages.table.subpages.drop.warning.prefix') }} + </span> <code class="code-key">{{ table.internal_name }}</code> - <span v-text="$t('pages.table.subpages.drop.warning.suffix')" /> + <span> + {{ $t('pages.table.subpages.drop.warning.suffix') }} + </span> </v-col> </v-row> <v-row> diff --git a/dbrepo-ui/components/dialogs/EditAccess.vue b/dbrepo-ui/components/dialogs/EditAccess.vue index 8132adddf5935ae357893f8f91a2c4c597e6cf94..039b1c40e8e5d241b1d52f6145affad898581702 100644 --- a/dbrepo-ui/components/dialogs/EditAccess.vue +++ b/dbrepo-ui/components/dialogs/EditAccess.vue @@ -12,14 +12,13 @@ <v-col> <v-autocomplete v-if="!isModification" - v-model="modify.userId" + v-model="localUserId" :items="eligibleUsers" :disabled="loadingUsers" :loading="loadingUsers" :rules="[v => !!v || $t('validation.required')]" required :variant="inputVariant" - hide-no-data hide-selected hide-details item-value="id" @@ -56,7 +55,7 @@ :disabled="!valid || loading || accessType === modify.type" :color="buttonColor" type="submit" - :text="$t('pages.database.subpages.access.submit.text')" + :text="$t('navigation.modify')" :loading="loading" @click="updateAccess" /> </v-card-actions> @@ -90,6 +89,7 @@ export default { loadingUsers: false, users: [], error: false, + localUserId: null, types: [ { title: this.$t('pages.database.subpages.access.read'), value: 'read' }, { title: this.$t('pages.database.subpages.access.write-own'), value: 'write_own' }, @@ -169,36 +169,48 @@ export default { }, revokeAccess () { const accessService = useAccessService() - accessService.remove(this.$route.params.database_id, this.userId) + accessService.remove(this.$route.params.database_id, this.localUserId) .then(() => { const toast = useToastInstance() - toast.success(this.$t('notifications.access.revoked')) + toast.success(this.$t('success.access.revoked')) this.$emit('close-dialog', { success: true }) }) + .catch(({code, message}) => { + const toast = useToastInstance() + toast.error(message) + }) .finally(() => { this.loading = false }) }, modifyAccess () { const accessService = useAccessService() - accessService.modify(this.$route.params.database_id, this.userId, this.modify) + accessService.modify(this.$route.params.database_id, this.localUserId, this.modify) .then(() => { const toast = useToastInstance() - toast.success(this.$t('notifications.access.modified')) + toast.success(this.$t('success.access.modified')) this.$emit('close-dialog', { success: true }) }) + .catch(({code, message}) => { + const toast = useToastInstance() + toast.error(message) + }) .finally(() => { this.loading = false }) }, giveAccess () { const accessService = useAccessService() - accessService.create(this.$route.params.database_id, this.userId, this.modify) + accessService.create(this.$route.params.database_id, this.localUserId, this.modify) .then(() => { const toast = useToastInstance() - toast.success(this.$t('notifications.access.created')) + toast.success(this.$t('success.access.created')) this.$emit('close-dialog', { success: true }) }) + .catch(({code, message}) => { + const toast = useToastInstance() + toast.error(message) + }) .finally(() => { this.loading = false }) @@ -210,6 +222,10 @@ export default { .then((users) => { this.users = users.filter(u => u.username !== this.database.creator.username) }) + .catch(({code}) => { + const toast = useToastInstance() + toast.error(this.$t(code)) + }) .finally(() => { this.loadingUsers = false }) @@ -217,6 +233,8 @@ export default { init () { if (!this.userId) { this.loadUsers() + } else { + this.localUserId = this.userId } if (!this.accessType) { this.modify.type = null diff --git a/dbrepo-ui/components/dialogs/EditTuple.vue b/dbrepo-ui/components/dialogs/EditTuple.vue index 589c82b9b7aee5d2678e9ceab8249618878ced3f..ea0bfb3c5b9161a907c2ca61544daafb737dd128 100644 --- a/dbrepo-ui/components/dialogs/EditTuple.vue +++ b/dbrepo-ui/components/dialogs/EditTuple.vue @@ -17,14 +17,35 @@ <v-text-field v-if="isNumber(column)" v-model.number="tuple[column.internal_name]" - :disabled="(!edit && column.auto_generated)" + :disabled="!edit" persistent-hint :variant="inputVariant" :label="column.internal_name" :hint="hint(column)" :rules="rules(column)" :required="required(column)" - type="number" /><v-text-field + type="number"> + <template + v-slot:append> + {{ column.column_type.toUpperCase() }} + <NuxtLink + target="_blank" + class="ml-2" + :href="documentationLink(column)"> + <v-tooltip + location="bottom"> + <template + v-slot:activator="{ props }"> + <v-icon + v-bind="props" + icon="mdi-help-circle-outline" /> + </template> + {{ $t('navigation.help') }} + </v-tooltip> + </NuxtLink> + </template> + </v-text-field> + <v-text-field v-if="isTextField(column)" v-model="tuple[column.internal_name]" :disabled="disabled(column)" @@ -37,7 +58,27 @@ :variant="inputVariant" :label="column.internal_name" :hint="hint(column)" - type="text" /> + type="text"> + <template + v-slot:append> + {{ column.column_type.toUpperCase() }} + <NuxtLink + target="_blank" + class="ml-2" + :href="documentationLink(column)"> + <v-tooltip + location="bottom"> + <template + v-slot:activator="{ props }"> + <v-icon + v-bind="props" + icon="mdi-help-circle-outline" /> + </template> + {{ $t('navigation.help') }} + </v-tooltip> + </NuxtLink> + </template> + </v-text-field> <v-text-field v-if="isFloatingPoint(column)" v-model="tuple[column.internal_name]" @@ -50,7 +91,27 @@ :variant="inputVariant" :label="column.internal_name" :hint="hint(column)" - type="number" /> + type="number"> + <template + v-slot:append> + {{ column.column_type.toUpperCase() }} + <NuxtLink + target="_blank" + class="ml-2" + :href="documentationLink(column)"> + <v-tooltip + location="bottom"> + <template + v-slot:activator="{ props }"> + <v-icon + v-bind="props" + icon="mdi-help-circle-outline" /> + </template> + {{ $t('navigation.help') }} + </v-tooltip> + </NuxtLink> + </template> + </v-text-field> <v-textarea v-if="isTextArea(column)" v-model="tuple[column.internal_name]" @@ -62,7 +123,27 @@ persistent-hint :variant="inputVariant" :label="column.internal_name" - :hint="hint(column)" /> + :hint="hint(column)"> + <template + v-slot:append> + {{ column.column_type.toUpperCase() }} + <NuxtLink + target="_blank" + class="ml-2" + :href="documentationLink(column)"> + <v-tooltip + location="bottom"> + <template + v-slot:activator="{ props }"> + <v-icon + v-bind="props" + icon="mdi-help-circle-outline" /> + </template> + {{ $t('navigation.help') }} + </v-tooltip> + </NuxtLink> + </template> + </v-textarea> <BlobUpload v-if="isFileField(column)" :column="column" @@ -77,7 +158,27 @@ :rules="rules(column)" :required="required(column)" :clearable="!required(column)" - :items="isSet(column) ? column.sets : column.enums" /> + :items="isSet(column) ? column.sets : column.enums"> + <template + v-slot:append> + {{ column.column_type.toUpperCase() }} + <NuxtLink + target="_blank" + class="ml-2" + :href="documentationLink(column)"> + <v-tooltip + location="bottom"> + <template + v-slot:activator="{ props }"> + <v-icon + v-bind="props" + icon="mdi-help-circle-outline" /> + </template> + {{ $t('navigation.help') }} + </v-tooltip> + </NuxtLink> + </template> + </v-select> <v-select v-if="isBoolean(column)" v-model="tuple[column.internal_name]" @@ -88,7 +189,27 @@ :rules="rules(column)" :required="required(column)" :items="bools" - :clearable="!required(column)" /> + :clearable="!required(column)"> + <template + v-slot:append> + {{ column.column_type.toUpperCase() }} + <NuxtLink + target="_blank" + class="ml-2" + :href="documentationLink(column)"> + <v-tooltip + location="bottom"> + <template + v-slot:activator="{ props }"> + <v-icon + v-bind="props" + icon="mdi-help-circle-outline" /> + </template> + {{ $t('navigation.help') }} + </v-tooltip> + </NuxtLink> + </template> + </v-select> <v-text-field v-if="isTimeField(column)" v-model="tuple[column.internal_name]" @@ -97,7 +218,27 @@ persistent-hint :variant="inputVariant" :label="column.internal_name" - :hint="hint(column)" /> + :hint="hint(column)"> + <template + v-slot:append> + {{ column.column_type.toUpperCase() }} + <NuxtLink + target="_blank" + class="ml-2" + :href="documentationLink(column)"> + <v-tooltip + location="bottom"> + <template + v-slot:activator="{ props }"> + <v-icon + v-bind="props" + icon="mdi-help-circle-outline" /> + </template> + {{ $t('navigation.help') }} + </v-tooltip> + </NuxtLink> + </template> + </v-text-field> </v-col> </v-row> </v-card-text> @@ -175,13 +316,24 @@ export default { bools: [ { title: 'true', value: true }, { title: 'false', value: false } - ] + ], + cacheStore: useCacheStore() } }, mounted() { + this.$refs.form.validate() this.oldTuple = Object.assign({}, this.tuple) }, computed: { + database () { + return this.cacheStore.getDatabase + }, + columnTypes () { + if (!this.database) { + return [] + } + return this.database.container.image.data_types + }, title () { return (this.edit ? this.$t('toolbars.table.data.edit') : this.$t('toolbars.table.data.add')) + ' ' + this.$t('toolbars.table.data.tuple') }, @@ -203,24 +355,35 @@ export default { this.$emit('close', { success: false }) }, hint (column) { - const { is_null_allowed, auto_generated, is_primary_key, column_type, date_format, size, d } = column - let hint = is_null_allowed ? '' : this.$t('pages.table.subpages.data.required.hint') - if (auto_generated) { + const { is_null_allowed, is_primary_key } = column + let hint = '' + if (!is_null_allowed) { + hint += this.$t('pages.table.subpages.data.required.hint') + } + if (column.column_type === 'sequence') { hint += ' ' + this.$t('pages.table.subpages.data.auto.hint') } if (is_primary_key) { hint += ' ' + this.$t('pages.table.subpages.data.primary-key.hint') } - if (['double', 'decimal'].includes(column_type)) { - hint += ' ' + this.$t('pages.table.subpages.data.format.hint') + ` ${'d'.repeat(size)}.${'f'.repeat(d)}` + if (this.formatHint(column)) { + hint += this.$t('pages.table.subpages.data.format.hint') + ' ' + this.formatHint(column) } - if (['date', 'datetime', 'timestamp', 'time'].includes(column_type) && date_format) { - hint += ' ' + this.$t('pages.table.subpages.data.format.hint') + ' ' + date_format.unix_format + return hint + }, + documentationLink ({column_type}) { + const filter = this.columnTypes.filter(t => t.value === column_type) + if (filter.length !== 1) { + return null } - if (['year'].includes(column_type)) { - hint += ' ' + this.$t('pages.table.subpages.data.format.hint') + ' YYYY' + return filter[0].documentation + }, + formatHint ({column_type}) { + const filter = this.columnTypes.filter(t => t.value === column_type) + if (filter.length !== 1) { + return null } - return hint + return filter[0].data_hint }, isTextField (column) { const { column_type } = column @@ -251,14 +414,14 @@ export default { return ['date', 'datetime', 'timestamp', 'time', 'year'].includes(column.column_type) }, rules (column) { - if (column.auto_generated || column.is_null_allowed) { + if (column.is_null_allowed) { return [] } const rules = [] rules.push(v => v !== null || this.$t('validation.required')) if (column.column_type === 'decimal' || column.column_type === 'double') { rules.push(v => !(!v || v.split('.')[0].length > column.size) || `${this.$t('pages.table.subpages.data.float.max')} ${column.size} ${this.$t('pages.table.subpages.data.float.before')}`) - rules.push(v => !(!v || v.split('.')[1].length > column.d) || `${this.$t('pages.table.subpages.data.float.max')} ${column.d} ${this.$t('pages.table.subpages.data.float.after')}`) + rules.push(v => !(!v || (column.d && v.split('.')[1].length > column.d)) || `${this.$t('pages.table.subpages.data.float.max')} ${column.d} ${this.$t('pages.table.subpages.data.float.after')}`) } return rules }, @@ -272,7 +435,7 @@ export default { return column.is_null_allowed === false }, disabled (column) { - return (this.edit && column.is_primary_key) || (!this.edit && column.auto_generated) + return (this.edit && column.is_primary_key) || !this.edit }, updateTuple () { const constraints = {} diff --git a/dbrepo-ui/components/dialogs/Semantics.vue b/dbrepo-ui/components/dialogs/Semantics.vue index a4a7104788ce1e12460ad693ac543058b60cdf6c..8d3c573f7b205368fd354372a9e166f2ee81a14f 100644 --- a/dbrepo-ui/components/dialogs/Semantics.vue +++ b/dbrepo-ui/components/dialogs/Semantics.vue @@ -12,14 +12,21 @@ <v-alert border="start" color="info"> - <p - v-text="$t('pages.table.subpages.semantics.info')" /> + <p> + {{ $t('pages.table.subpages.semantics.info') }} + </p> <p class="mt-1" v-for="(ontology, idx) in ontologies" :key="`o-${idx}`"> - <v-badge inline :content="badge(ontology).text" :color="badge(ontology).color"> - <a :href="ontology.uri" v-text="ontology.uri_pattern" /> + <v-badge + inline + :content="badge(ontology).text" + :color="badge(ontology).color"> + <a + :href="ontology.uri"> + {{ ontology.uri_pattern }} + </a> </v-badge> </p> </v-alert> @@ -34,11 +41,13 @@ color="info"> <p> <a - :href="entity.uri" - v-text="entity.name ? entity.name : entity.uri" /> + :href="entity.uri"> + {{ entity.name ? entity.name : entity.uri }} + </a> + </p> + <p> + {{ entity.description }} </p> - <p - v-text="entity.description" /> </v-alert> </v-col> </v-row> @@ -65,8 +74,9 @@ lines="one" v-model="recommendation" select-strategy="single-independent"> - <v-list-subheader - v-text="$t('pages.table.subpages.semantics.recommended')" /> + <v-list-subheader> + {{ $t('pages.table.subpages.semantics.recommended') }} + </v-list-subheader> <v-list-item v-for="(item, idx) in recommendations" :key="`r-${idx}`" @@ -77,8 +87,12 @@ <v-checkbox-btn :model-value="isActive"></v-checkbox-btn> </v-list-item-action> </template> - <v-list-item-title v-text="item.label" /> - <v-list-item-subtitle v-text="subtitle(item)" /> + <v-list-item-title> + {{ item.label }} + </v-list-item-title> + <v-list-item-subtitle> + {{ subtitle(item) }} + </v-list-item-subtitle> </v-list-item> </v-list> </v-col> diff --git a/dbrepo-ui/components/dialogs/ViewSemanticEntity.vue b/dbrepo-ui/components/dialogs/ViewSemanticEntity.vue index ede7fe25bcd421c0304f41d224be7615598a9251..41b69f89892e3068a781e5cac0ffafee767c473a 100644 --- a/dbrepo-ui/components/dialogs/ViewSemanticEntity.vue +++ b/dbrepo-ui/components/dialogs/ViewSemanticEntity.vue @@ -1,17 +1,32 @@ <template> <div> <v-card> - <v-card-title v-text="entity.name" /> + <v-card-title> + {{ entity.name }} + </v-card-title> <v-card-subtitle> - <a :href="entity.uri" target="_blank" v-text="entity.uri" /> + <a + :href="entity.uri" + target="_blank"> + {{ entity.uri }} + </a> </v-card-subtitle> <v-card-text> - <p v-text="description" /> + <p> + {{ description }} + </p> </v-card-text> - <div v-for="(item,idx) in entity.columns" :key="idx"> + <div + v-for="(item,idx) in entity.columns" + :key="idx"> <v-list-item two-line :to="link(item)"> - <v-list-item-title v-text="item.name" /> - <v-list-item-subtitle class="mt-2" v-text="link(item)" /> + <v-list-item-title> + {{ item.name }} + </v-list-item-title> + <v-list-item-subtitle + class="mt-2"> + {{ link(item) }} + </v-list-item-subtitle> </v-list-item> </div> <v-card-actions> diff --git a/dbrepo-ui/components/identifier/Citation.vue b/dbrepo-ui/components/identifier/Citation.vue index 6f35ac915e255610965015ccd16adcf1dad03597..7cd99194b099987f3853fde4afd7bf92f463dd38 100644 --- a/dbrepo-ui/components/identifier/Citation.vue +++ b/dbrepo-ui/components/identifier/Citation.vue @@ -1,7 +1,10 @@ <template> - <v-row no-gutters> - <v-col v-if="!loading" md="10"> - <pre v-text="citation" /> + <v-row + no-gutters> + <v-col + v-if="!loading" + md="10"> + <pre>{{ citation }}</pre> </v-col> <v-col v-if="!$vuetify.display.mdAndDown" diff --git a/dbrepo-ui/components/identifier/Creators.vue b/dbrepo-ui/components/identifier/Creators.vue index 706736b21b155f5dc0265b0993f23b435bd5c345..8aa5fac7aa7f06ca809179a3903a5e23830504e4 100644 --- a/dbrepo-ui/components/identifier/Creators.vue +++ b/dbrepo-ui/components/identifier/Creators.vue @@ -16,12 +16,14 @@ v-if="hasRor(personOrOrg)" class="mr-1" :ror="personOrOrg.name_identifier" /> - <span - v-text="personOrOrg.creator_name" /> + <span> + {{ personOrOrg.creator_name }} + </span> <sup v-if="hasAffiliation(personOrOrg)" - v-text="personOrOrg.affiliation_index" - class="ml-1" /> + class="ml-1"> + {{ personOrOrg.affiliation_index }} + </sup> <span v-if="!isLast(creators, i)">; </span> </span> @@ -30,7 +32,9 @@ <span v-for="(affiliation, i) in affiliations" :key="`c-${i}`"> - <sup v-text="i+1" /> + <sup> + {{ i+1 }} + </sup> {{ affiliation.name }} <RorIcon v-if="hasRor(affiliation)" diff --git a/dbrepo-ui/components/identifier/Persist.vue b/dbrepo-ui/components/identifier/Persist.vue index 0de61931265d5359c07637d935aa9101a1ebca6a..1795d058660ff08288b9054435e44362d84cf0e7 100644 --- a/dbrepo-ui/components/identifier/Persist.vue +++ b/dbrepo-ui/components/identifier/Persist.vue @@ -589,14 +589,20 @@ v-if="identifier.licenses.length > 0" color="tertiary"> <p> - <a :href="identifier.licenses[0].uri" target="_blank"> - <strong v-text="identifier.licenses[0].identifier" /> <sup><v-icon x-small>mdi-open-in-new</v-icon></sup> + <a + :href="identifier.licenses[0].uri" + target="_blank"> + <strong> + {{ identifier.licenses[0].identifier }} + </strong> + <sup><v-icon x-small>mdi-open-in-new</v-icon></sup> </a> </p> <p v-if="identifier.licenses[0].description" - class="mt-2" - v-text="identifier.licenses[0].description" /> + class="mt-2"> + {{ identifier.licenses[0].description }} + </p> </v-alert> </v-card-text> <v-card-text> @@ -755,7 +761,7 @@ <v-list-item> <v-list-item-title> {{ $t('pages.identifier.subpages.create.summary.record') }} {{ resourceHumanDescription.prefix }} - "<strong v-text="resourceHumanDescription.info" />" + "<strong>{{ resourceHumanDescription.info }}</strong>" </v-list-item-title> <template v-slot:prepend> <v-icon @@ -775,7 +781,7 @@ <v-list-item-title v-if="identifier.licenses.length > 0"> {{ $t('pages.identifier.subpages.create.summary.license') }} - "<strong v-text="identifier.licenses[0].identifier" />" + "<strong>{{ identifier.licenses[0].identifier }}</strong>" </v-list-item-title> <v-list-item-title v-else> @@ -791,7 +797,7 @@ v-if="identifier.publisher"> <v-list-item-title> {{ $t('pages.identifier.subpages.create.summary.publisher') }} - "<strong v-text="identifier.publisher" />" + "<strong>{{ identifier.publisher }}</strong>" </v-list-item-title> <template v-slot:prepend> <v-icon diff --git a/dbrepo-ui/components/identifier/Summary.vue b/dbrepo-ui/components/identifier/Summary.vue index f4a5f7c880fc9618093ca82726159e598c16d998..267693276c18cde26769f387ddc2f3f34ec97689 100644 --- a/dbrepo-ui/components/identifier/Summary.vue +++ b/dbrepo-ui/components/identifier/Summary.vue @@ -18,7 +18,9 @@ <p v-for="(title, i) in identifier.titles" :key="`t-${i}`"> - <span v-text="title.title" /> + <span> + {{ title.title }} + </span> </p> </v-list-item> <v-list-item @@ -28,32 +30,42 @@ v-for="(description, i) in identifier.descriptions" :key="`d-${i}`"> <div - v-text="description?.type" - class="text-subtitle-2" /> - <span v-text="description.description" /> + class="text-subtitle-2"> + {{ description?.type }} + </div> + <span> + {{ description.description }} + </span> </p> </v-list-item> <v-list-item :title="$t('pages.identifier.publisher.title')" density="compact"> - <div v-text="identifier.publisher" /> + <div> + {{ identifier.publisher }} + </div> </v-list-item> <v-list-item :title="$t('pages.identifier.creators.title')" density="compact"> - <Creators :person-or-orgs="identifier.creators" /> + <Creators + :person-or-orgs="identifier.creators" /> </v-list-item> <v-list-item v-if="identifierLang" :title="$t('pages.identifier.language.title')" density="compact"> - <div v-text="identifierLang" /> + <div> + {{ identifierLang }} + </div> </v-list-item> <v-list-item v-if="publication" :title="$t('pages.identifier.publication-date.title')" density="compact"> - <div v-text="publication" /> + <div> + {{ publication }} + </div> </v-list-item> <v-list-item v-if="identifier.related_identifiers && identifier.related_identifiers.length > 0" @@ -75,16 +87,19 @@ :key="`f-${i}`"> <a v-if="funder.funder_identifier" - v-text="funder.funder_name" - :href="funder.funder_identifier" /> + :href="funder.funder_identifier"> + {{ funder.funder_name }} + </a> <span v-if="funder.award_title" - class="ml-1" - v-text="funder.award_title" /> + class="ml-1"> + {{ funder.award_title }} + </span> <span v-if="funder.award_number" - class="ml-1" - v-text="`(${funder.award_number})`" /> + class="ml-1"> + ({{ funder.award_number }}) + </span> </p> </v-list-item> <v-list-item @@ -95,11 +110,14 @@ v-for="(license, i) in identifier.licenses" :key="`l-${i}`"> <span> - <span v-text="i > 0 ? ', ' : ''" /> + <span> + {{ i > 0 ? ', ' : '' }} + </span> <a v-if="license" - v-text="license.identifier" - :href="license.uri" /> + :href="license.uri"> + {{ license.identifier }} + </a> </span> </p> </v-list-item> diff --git a/dbrepo-ui/components/search/AdvancedSearch.vue b/dbrepo-ui/components/search/AdvancedSearch.vue index 17a2839c64ce4b7584591c64e1be8f00715d7f28..13de402e019f2a791f0233c4fc611164e46e20d8 100644 --- a/dbrepo-ui/components/search/AdvancedSearch.vue +++ b/dbrepo-ui/components/search/AdvancedSearch.vue @@ -110,7 +110,9 @@ v-if="isEligibleYearRangeSearch" dense> <v-col> - <p v-text="$t('pages.search.publication-range.hint')" /> + <p> + {{ $t('pages.search.publication-range.hint') }} + </p> </v-col> </v-row> <v-row @@ -125,7 +127,9 @@ :hint="$t('pages.search.start-year.hint')" :variant="inputVariant" required - :rules="[v => !!v || $t('validation.required')]" + :rules="[ + v => !!v || $t('validation.required') + ]" clearable /> </v-col> <v-col cols="3"> @@ -144,12 +148,17 @@ <v-col> <p v-if="isEligibleUnitIndependentSearch" - v-text="$t('pages.search.concept-unit.hint')" - class="mt-4" /> + class="mt-4"> + {{ $t('pages.search.concept-unit.hint') }} + </p> </v-col> </v-row> - <v-row v-if="isEligibleConceptOrUnitSearch || isEligibleUnitIndependentSearch" dense> - <v-col v-if="isEligibleConceptOrUnitSearch || isEligibleUnitIndependentSearch" cols="3"> + <v-row + v-if="isEligibleConceptOrUnitSearch || isEligibleUnitIndependentSearch" + dense> + <v-col + v-if="isEligibleConceptOrUnitSearch || isEligibleUnitIndependentSearch" + cols="3"> <v-select v-model="advancedSearchData['tables.columns.concept.uri']" clearable @@ -162,7 +171,9 @@ :label="$t('pages.search.concept.label')" :hint="$t('pages.search.concept.hint')" /> </v-col> - <v-col v-if="isEligibleConceptOrUnitSearch || isEligibleUnitIndependentSearch" cols="3"> + <v-col + v-if="isEligibleConceptOrUnitSearch || isEligibleUnitIndependentSearch" + cols="3"> <v-select v-model="advancedSearchData['tables.columns.unit.uri']" clearable @@ -175,7 +186,9 @@ :label="$t('pages.search.unit.label')" :hint="$t('pages.search.unit.hint')" /> </v-col> - <v-col v-if="isEligibleUnitIndependentSearch" cols="3"> + <v-col + v-if="isEligibleUnitIndependentSearch" + cols="3"> <v-text-field v-model="advancedSearchData['t1']" clearable @@ -185,7 +198,9 @@ :label="$t('pages.search.start.label')" :hint="$t('pages.search.start.hint')" /> </v-col> - <v-col v-if="isEligibleUnitIndependentSearch" cols="3"> + <v-col + v-if="isEligibleUnitIndependentSearch" + cols="3"> <v-text-field v-model="advancedSearchData['t2']" clearable @@ -196,7 +211,8 @@ :hint="$t('pages.search.end.hint')" /> </v-col> </v-row> - <v-row dense> + <v-row + dense> <v-col> <v-btn type="submit" @@ -205,8 +221,9 @@ :loading="loading" :disabled="!valid || loading || loadingFields" size="small" - :text="$t('navigation.search')" - @click="advancedSearch" /> + @click="advancedSearch"> + {{ $t('navigation.search') }} + </v-btn> </v-col> </v-row> </v-form> diff --git a/dbrepo-ui/components/subset/Builder.vue b/dbrepo-ui/components/subset/Builder.vue index 7c30fd8f5a488cee4173f710e50e50e0154e9210..a6f53c6e4f0dba0ef1f8935c9112dc1e2d1d0df2 100644 --- a/dbrepo-ui/components/subset/Builder.vue +++ b/dbrepo-ui/components/subset/Builder.vue @@ -123,7 +123,23 @@ :rules="[v => !!v || $t('validation.required')]" return-object multiple - @update:model-value="buildQuery" /> + @update:model-value="buildQuery"> + <template + v-slot:prepend-item> + <v-list-item + title="Select All" + :active="select.length === columns.length" + @click="toggleColumns"> + <template + v-slot:prepend> + <v-checkbox-btn + :model-value="select.length === columns.length" /> + </template> + </v-list-item> + <v-divider + class="mt-2" /> + </template> + </v-select> </v-col> </v-row> <v-row v-if="select.length > 0"> @@ -194,7 +210,7 @@ <v-col md="8" class="text-center"> - <pre v-text="clause.type.toUpperCase()" /> + <pre>{{ clause.type.toUpperCase() }}</pre> </v-col> </v-row> <div @@ -233,13 +249,17 @@ <v-alert border="start" color="warning"> - <span v-text="$t('pages.subset.subpages.create.expert.warn')" /> - <pre style="white-space:inherit;" v-text="unsupported.join(', ')" /> + <span> + {{ $t('pages.subset.subpages.create.expert.warn') }} + </span> + <pre style="white-space:inherit;">{{ unsupported.join(', ') }}</pre> </v-alert> </v-col> </v-row> <v-row dense> - <v-col v-text="$t('pages.subset.subpages.create.subtitle')" /> + <v-col> + {{ $t('pages.subset.subpages.create.subtitle') }} + </v-col> </v-row> <v-row dense> <v-col> @@ -370,6 +390,12 @@ export default { database () { return this.cacheStore.getDatabase }, + columnTypes () { + if (!this.database) { + return [] + } + return this.database.container.image.data_types + }, user () { return this.userStore.getUser }, @@ -533,7 +559,7 @@ export default { return } const queryService = useQueryService() - const { error, reason, column, raw, formatted } = queryService.build(this.table.internal_name, this.select, this.clauses) + const { error, reason, column, raw, formatted } = queryService.build(this.table.internal_name, this.select, this.columnTypes, this.clauses) if (error) { const toast = useToastInstance() toast.error(this.$t('error.query.' + reason) + ' ' + column) @@ -584,6 +610,14 @@ export default { keywordCase: 'upper' }) } + }, + toggleColumns () { + if (this.select.length !== this.columns.length) { + this.select = this.columns + this.buildQuery() + } else { + this.select = [] + } } } } diff --git a/dbrepo-ui/components/subset/Results.vue b/dbrepo-ui/components/subset/Results.vue index 95becef12c4f0e5116345f1ade444fb36f350fb3..4ba414309c5009bdf88914150b6c1afe11e9a65e 100644 --- a/dbrepo-ui/components/subset/Results.vue +++ b/dbrepo-ui/components/subset/Results.vue @@ -8,6 +8,7 @@ :items="result.rows" :items-length="total" :footer-props="footerProps" + :items-per-page-options="footerProps.itemsPerPageOptions" @update:options="updateOptions" /> </div> </template> diff --git a/dbrepo-ui/components/subset/SubsetToolbar.vue b/dbrepo-ui/components/subset/SubsetToolbar.vue index 5c5081a2f8f5c3944928bbd59cd76dddc2c79d89..db9452feaac3c78e879e3ca157034ea8c87da6dc 100644 --- a/dbrepo-ui/components/subset/SubsetToolbar.vue +++ b/dbrepo-ui/components/subset/SubsetToolbar.vue @@ -166,11 +166,17 @@ export default { } return this.subset.creator.username === this.username }, + hasReadAccess () { + if (!this.access) { + return false + } + return this.access.type === 'read' || this.access.type === 'write_all' || this.access.type === 'write_own' + }, canGetPid () { if (!this.user || !this.subset || !this.database) { return false } - return this.database.owner.id === this.user.id || (this.subset.creator.id === this.user.id && UserUtils.hasReadAccess(this.access)) + return this.database.owner.id === this.user.id || (this.subset.creator.id === this.user.id && this.hasReadAccess) }, title () { if (!this.identifier) { diff --git a/dbrepo-ui/components/table/BlobDownload.vue b/dbrepo-ui/components/table/BlobDownload.vue index 6ae215e95bf782447f0b0261b470af531a378083..7a96b5e27ba1c738da29770c0b667c3f558d3d9d 100644 --- a/dbrepo-ui/components/table/BlobDownload.vue +++ b/dbrepo-ui/components/table/BlobDownload.vue @@ -1,6 +1,6 @@ <template> <div> - <pre v-text="description" /> + <pre>{{ description }}</pre> </div> </template> diff --git a/dbrepo-ui/components/table/TableHistory.vue b/dbrepo-ui/components/table/TableHistory.vue index dd3dad66e2961b59f5591a586150e88fa2c00ff6..34d45248e7341b9a5b8b3af1c2d799e4408e6ecb 100644 --- a/dbrepo-ui/components/table/TableHistory.vue +++ b/dbrepo-ui/components/table/TableHistory.vue @@ -28,6 +28,10 @@ :options="chartOptions" :height="200" :width="400" /> + <pre>{{ history }}</pre> + <p> + {{ $t('pages.table.subpages.versioning.chart.legend') }} + </p> </v-card-text> <v-card-actions> <v-spacer /> @@ -52,9 +56,9 @@ </template> <script> +import { UTCDate } from '@date-fns/utc' import { Bar } from 'vue-chartjs' import { format } from 'date-fns' -import { useCacheStore } from '~/stores/cache.js' import { Chart as ChartJS, Title, Tooltip, BarElement, CategoryScale, LinearScale, LogarithmicScale } from 'chart.js' ChartJS.register(Title, Tooltip, BarElement, CategoryScale, LinearScale, LogarithmicScale) @@ -69,6 +73,7 @@ export default { loading: true, datetime: null, history: null, + chartData: null, chartOptions: { responsive: true, onClick: this.handle, @@ -92,7 +97,7 @@ export default { }, }, x: { - display: true, + display: false, ticks: { min: 0, stepSize: 1 @@ -118,15 +123,6 @@ export default { buttonVariant () { const runtimeConfig = useRuntimeConfig() return this.$vuetify.theme.global.name.toLowerCase().endsWith('contrast') ? runtimeConfig.public.variant.button.contrast : runtimeConfig.public.variant.button.normal - }, - chartData () { - return { - labels: this.history ? this.history.map(d => format(new Date(d.timestamp), 'yyyy-MM-dd HH:mm:ss')) : [], - datasets: [ - this.history ? { backgroundColor: this.$vuetify.theme.current.colors.success, data: this.history.filter(d => d.event === 'INSERT').map(d => d.total) } : { data: [] }, - this.history ? { backgroundColor: this.$vuetify.theme.current.colors.error, data: this.history.filter(d => d.event === 'DELETE').map(d => d.total) } : { data: [] }, - ] - } } }, mounted() { @@ -153,13 +149,28 @@ export default { this.datetime = this.chartData.labels[idx] console.debug('date time', this.datetime, 'idx', idx) }, + filterHistoryEventType (history, type) { + return history.map(d => { + if (d.event === type) { + return d.total + } + return null + }) + }, loadHistory () { this.loading = true const tableService = useTableService() tableService.history(this.table.database_id, this.table.id) .then((history) => { this.loading = false - this.history = history + this.chartData = { + // labels: history ? history.map(d => format(new UTCDate(d.timestamp), 'yyyy-MM-dd HH:mm:ss.SSS')) : [], + labels: history ? history.map(d => format(new UTCDate(d.timestamp), 'yyyy-MM-dd HH:mm:ss')) : [], + datasets: [ + { backgroundColor: this.$vuetify.theme.current.colors.success, data: this.filterHistoryEventType(history, 'INSERT') }, + { backgroundColor: this.$vuetify.theme.current.colors.error, data: this.filterHistoryEventType(history, 'DELETE') } + ] + } }) .catch(({message}) => { const toast = useToastInstance() diff --git a/dbrepo-ui/components/table/TableImport.vue b/dbrepo-ui/components/table/TableImport.vue index 2451a7c3acb18722e8e4b0ebdb9fe10effcd554d..84c1011c9b24842c7bb1ed563919af61f6211833 100644 --- a/dbrepo-ui/components/table/TableImport.vue +++ b/dbrepo-ui/components/table/TableImport.vue @@ -83,39 +83,6 @@ </v-select> </v-col> </v-row> - <v-row dense> - <v-col md="8"> - <v-text-field - v-model="tableImport.null_element" - clearable - persistent-hint - :variant="inputVariant" - :hint="$t('pages.table.subpages.import.null.hint')" - :label="$t('pages.table.subpages.import.null.label')"/> - </v-col> - </v-row> - <v-row dense> - <v-col md="8"> - <v-text-field - v-model="tableImport.true_element" - clearable - persistent-hint - :variant="inputVariant" - :hint="$t('pages.table.subpages.import.true.hint')" - :label="$t('pages.table.subpages.import.true.label')"/> - </v-col> - </v-row> - <v-row dense> - <v-col md="8"> - <v-text-field - v-model="tableImport.false_element" - clearable - persistent-hint - :variant="inputVariant" - :hint="$t('pages.table.subpages.import.false.hint')" - :label="$t('pages.table.subpages.import.false.label')"/> - </v-col> - </v-row> </v-container> </v-form> </v-stepper-window> @@ -132,8 +99,9 @@ v-if="$route.query.location" dense> <v-col> - <p - v-text="$t('pages.table.subpages.import.storage.text')" /> + <p> + {{ $t('pages.table.subpages.import.storage.text') }} + </p> <v-chip prepend-icon="mdi-cloud-upload" label> @@ -149,14 +117,19 @@ <v-row v-if="step > 1 && suggestedAnalyseSeparator && providedSeparator !== analysedSeparator" dense> - <v-col> + <v-col + md="8"> <v-alert border="start" color="warning"> {{ $t('pages.table.subpages.import.separator.warn.prefix') }} - <strong v-text="tableImport.separator"/> + <strong> + {{ tableImport.separator }} + </strong> {{ $t('pages.table.subpages.import.separator.warn.middle') }} - <strong v-text="suggestedAnalyseSeparator"/> + <strong> + {{ suggestedAnalyseSeparator }} + </strong> {{ $t('pages.table.subpages.import.separator.warn.suffix') }} </v-alert> </v-col> @@ -164,7 +137,8 @@ <v-row v-if="step > 1 && suggestedAnalyseLineTerminator && providedTerminator !== analysedTerminator" dense> - <v-col> + <v-col + md="8"> <v-alert border="start" color="warning"> @@ -261,23 +235,22 @@ direction="vertical"> <v-container> <v-row - v-if="rowCount" dense> <v-col md="8"> <v-alert border="start" color="success"> - <span v-text="$t(`pages.table.subpages.import.summary.prefix`)"/> - <strong> {{ rowCount }} </strong> - <span v-text="$t('pages.table.subpages.import.summary.suffix')"/> + <span> + {{ $t(`pages.table.subpages.import.summary.text`)}} + </span> </v-alert> </v-col> </v-row> <v-row> <v-col> <v-btn - v-if="rowCount !== null" + v-if="step === 3" color="secondary" :disabled="step !== 3 || disabled" size="small" @@ -329,9 +302,6 @@ export default { tableImport: { location: null, quote: '"', - false_element: null, - true_element: null, - null_element: '', separator: ',', line_termination: '\\n', skip_lines: 1 @@ -357,9 +327,6 @@ export default { this.cacheStore.setUploadProgress(null) this.setQueryParamSafely('location') this.setQueryParamSafely('quote') - this.setQueryParamSafely('false_element') - this.setQueryParamSafely('true_element') - this.setQueryParamSafely('null_element') this.setQueryParamSafely('separator') this.setQueryParamSafely('line_termination') this.setQueryParamSafely('skip_lines') @@ -457,10 +424,6 @@ export default { const toast = useToastInstance() toast.success(this.$t('success.import.dataset')) this.cacheStore.reloadDatabase() - tableService.getCount(this.$route.params.database_id, this.tableId, null) - .then((rowCount) => { - this.rowCount = rowCount - }) this.step = 3 this.validStep3 = true this.loadingImport = false @@ -542,13 +505,10 @@ export default { this.$emit('analyse', { columns: this.columns, filename, - line_termination, + line_termination: line_termination === '\\n' ? '\n' : JSON.stringify(line_termination).replaceAll('"', ''), separator: this.tableImport.separator, skip_lines: this.tableImport.skip_lines, quote: this.tableImport.quote, - null_element: this.tableImport.null_element, - true_element: this.tableImport.true_element, - false_element: this.tableImport.false_element }) this.loading = false }) diff --git a/dbrepo-ui/components/table/TableList.vue b/dbrepo-ui/components/table/TableList.vue index 362f4a93665161b36a432d147fb862890c389f1a..2fc2c7d791b5ce5f84614bc9e2266d99c4c49e9b 100644 --- a/dbrepo-ui/components/table/TableList.vue +++ b/dbrepo-ui/components/table/TableList.vue @@ -60,7 +60,6 @@ export default { { value: 'is_primary_key', title: 'Primary Key' }, { value: 'unique', title: 'Unique' }, { value: 'is_null_allowed', title: 'Nullable' }, - { value: 'auto_generated', title: 'Sequence' } ], columnTypes: [ // { value: 'ENUM', text: 'Enumeration' }, // Disabled for now, not implemented, #145 diff --git a/dbrepo-ui/components/table/TableSchema.vue b/dbrepo-ui/components/table/TableSchema.vue index 8539962de5cdea84ee523ab2f65255fd9f66ab7a..09a044c6ff4b0f9317a62638cb32a002cc93e8a4 100644 --- a/dbrepo-ui/components/table/TableSchema.vue +++ b/dbrepo-ui/components/table/TableSchema.vue @@ -48,7 +48,10 @@ <v-text-field v-model="c.name" required - :rules="[v => !!v || $t('validation.required')]" + :rules="[ + v => !!v || $t('validation.required'), + v => this.columns.filter(column => column.name === v).length === 1 || $t('validation.column.exists') + ]" persistent-hint :variant="inputVariant" :label="$t('pages.table.subpages.schema.name.label')" @@ -60,7 +63,7 @@ <v-select v-model="c.type" :items="columnTypes" - item-title="text" + item-title="display_name" item-value="value" required :rules="[v => !!v || $t('validation.required')]" @@ -68,7 +71,7 @@ :variant="inputVariant" :label="$t('pages.table.subpages.schema.type.label')" :hint="$t('pages.table.subpages.schema.type.hint')" - @update:model-value="setDefaultSizeAndD(c);updateColumnMatch(c)" /> + @update:modelValue="setDefaultSizeAndD(c);updateColumnMatch(c)" /> <!-- ;so.changeSourceDatatype(idx, c) --> </v-col> <v-col @@ -105,28 +108,43 @@ <!-- v-on:change="so.changeEnumValues(idx, c)" --> </v-col> <v-col - v-if="defaultSize(c) !== false" + v-if="columnType(c) && columnType(c).size_required !== null" cols="1"> <v-text-field v-model.number="c.size" type="number" - required + :min="columnType(c).size_min" + :max="columnType(c).size_max" + :step="columnType(c).size_step" + :value="columnType(c).size_required === true ? columnType(c).size_default : null" + :hint="sizeHint(c)" + :clearable="!columnType(c).size_required" + persistent-hint :variant="inputVariant" - :rules="[v => (v !== null && v !== '') || $t('validation.required')]" + :rules="[ + v => !(columnType(c).size_required && (v === null || v === '')) || $t('validation.required') + ]" :error-messages="sizeErrorMessages(c)" - :label="$t('pages.table.subpages.schema.size.label')"/> + :label="$t('pages.table.subpages.schema.size.label')" /> </v-col> <v-col - v-if="defaultD(c) !== false" + v-if="columnType(c) && columnType(c).d_required !== null" cols="1"> <v-text-field v-model.number="c.d" type="number" - required + :min="columnType(c).d_min !== null ? columnType(c).d_min : null" + :max="columnType(c).d_max !== null ? columnType(c).d_max : null" + :step="columnType(c).d_step" + :hint="dHint(c)" + :clearable="!columnType(c).d_required" + persistent-hint :variant="inputVariant" - :rules="[v => (v !== null && v !== '') || $t('validation.required')]" + :rules="[ + v => !(columnType(c).d_required && (v === null || v === '')) || $t('validation.required') + ]" :error-messages="dErrorMessages(c)" - :label="$t('pages.table.subpages.schema.d.label')"/> + :label="$t('pages.table.subpages.schema.d.label')" /> </v-col> <v-col cols="2" @@ -140,11 +158,11 @@ :items="filterDateFormats(c)" item-title="unix_format" item-value="id" - :label="$t('pages.table.subpages.schema.fsp.label')"/> + :label="$t('pages.table.subpages.schema.fsp.label')" /> </v-col> <v-col v-if="shift(c)" - :cols="shift(c)"/> + :cols="shift(c)" /> <v-col cols="1"> <v-select @@ -194,24 +212,24 @@ v-model="c.primary_key" :disabled="disabled" :label="$t('pages.table.subpages.schema.primary-key.label')" - @click="setOthers(c)"/> + @click="setOthers(c)" /> </v-col> <v-col cols="auto" class="pl-10"> <v-checkbox v-model="c.null_allowed" - :disabled="c.primary_key || disabled" - :label="$t('pages.table.subpages.schema.null.label')"/> + :disabled="c.primary_key || c.type === 'serial' || disabled" + :label="$t('pages.table.subpages.schema.null.label')" /> </v-col> <v-col cols="auto" class="pl-10"> <v-checkbox v-model="c.unique" - :disabled="disabled" + :disabled="disabled || c.type === 'serial'" :hidden="c.primary_key" - :label="$t('pages.table.subpages.schema.unique.label')"/> + :label="$t('pages.table.subpages.schema.unique.label')" /> </v-col> <v-col v-if="canRemove(idx)" @@ -223,7 +241,7 @@ variant="flat" :disabled="disabled" :text="$t('pages.table.subpages.schema.remove.text')" - @click="removeColumn(idx)"/> + @click="removeColumn(idx)" /> </v-col> </v-row> <v-row> @@ -234,7 +252,7 @@ :variant="buttonVariant" :disabled="disabled" :text="$t('pages.table.subpages.schema.add.text')" - @click="addColumn()"/> + @click="addColumn()" /> </v-col> </v-row> <v-row @@ -254,9 +272,9 @@ variant="flat" size="small" :loading="loading" - :disabled="disabled || !valid || this.columns.length === 0" + :disabled="disabled || !valid || showPrimaryKeyWarning || this.columns.length === 0" :text="submitText" - @click="submit"/> + @click="submit" /> </v-col> </v-row> </v-form> @@ -271,25 +289,25 @@ export default { props: { columns: { type: Array, - default() { + default () { return [] } }, disabled: { type: Boolean, - default() { + default () { return false } }, loading: { type: Boolean, - default() { + default () { return false } }, submitText: { type: String, - default() { + default () { return null } }, @@ -300,7 +318,7 @@ export default { } } }, - data() { + data () { return { schema_id: null, timestamp: null, @@ -322,29 +340,38 @@ export default { valid: false, tableColumns: [], extractor: useExtractorService(), - columnTypes: useQueryService().mySql8DataTypes(), cacheStore: useCacheStore() } }, computed: { - database() { + database () { return this.cacheStore.getDatabase }, - dateFormats() { + columnTypes () { + if (!this.database) { + return [] + } + const types = this.database.container.image.data_types + if (this.columns.filter(c => c.type === 'serial').length > 0) { + return types.filter(t => t.value !== 'serial') + } + return types + }, + dateFormats () { if (!this.database || !('container' in this.database) || !('image' in this.database.container) || !('date_formats' in this.database.container.image)) { return [] } return this.database.container.image.date_formats }, - inputVariant() { + inputVariant () { const runtimeConfig = useRuntimeConfig() return this.$vuetify.theme.global.name.toLowerCase().endsWith('contrast') ? runtimeConfig.public.variant.input.contrast : runtimeConfig.public.variant.input.normal }, - buttonVariant() { + buttonVariant () { const runtimeConfig = useRuntimeConfig() return this.$vuetify.theme.global.name.toLowerCase().endsWith('contrast') ? runtimeConfig.public.variant.button.contrast : runtimeConfig.public.variant.button.normal }, - showPrimaryKeyWarning() { + showPrimaryKeyWarning () { return this.columns.filter(c => c.primary_key).length === 0 }, conceptOntologyHeaders() { @@ -364,7 +391,7 @@ export default { }, watch: { valid: { - handler() { + handler () { this.$emit('schema-valid', { valid: this.valid }) } }, @@ -381,34 +408,28 @@ export default { this.updateMatch() }, methods: { - shift(column) { + shift (column) { if (!this.columns || this.columns.length === 0) { return false } let shift = 0 - if (this.hasDate(column) === false && this.columns.filter(c => this.hasDate(c) !== false).length > 0) { + if (!this.hasEnumOrSet(column) && (this.columnType(column).size_required === null || this.columnType(column).size_required === undefined) && this.columns.filter(c => (this.columnType(c).size_required !== null || this.columnType(c).size_required !== undefined)).length > 0) { shift++ } - if (this.defaultSize(column) === false && this.columns.filter(c => this.defaultSize(c) !== false).length > 0) { - shift++ - } - if (this.defaultD(column) === false && this.columns.filter(c => this.defaultD(c) !== false).length > 0) { - shift++ - } - if (this.hasEnumOrSet(column) === false && this.columns.filter(c => this.hasEnumOrSet(c) !== false).length > 0) { + if (!this.hasEnumOrSet(column) && (this.columnType(column).d_required === null || this.columnType(column).d_required === undefined) && this.columns.filter(c => (this.columnType(c).d_required !== null || this.columnType(c).d_required !== undefined)).length > 0) { shift++ } return shift }, - submit() { + submit () { const tableService = useTableService() this.$emit('close', { success: true, columns: tableService.prepareColumns(this.columns), constraints: tableService.prepareConstraints(this.columns) }) }, - setOthers(column) { + setOthers (column) { column.null_allowed = false column.unique = true }, - canRemove(idx) { + canRemove (idx) { if (idx > 0) { return true } @@ -417,10 +438,10 @@ export default { } return false }, - removeColumn(idx) { + removeColumn (idx) { this.columns.splice(idx, 1) }, - addColumn (name = null, type = null, null_allowed = true, primary_key = false, unique = false) { + addColumn (name = '', type = null, null_allowed = true, primary_key = false, unique = false) { this.columns.push({ name, type, @@ -430,7 +451,6 @@ export default { unit: null, null_allowed, primary_key, - dfid: null, sets: [], sets_values: null, enums: [], @@ -440,7 +460,7 @@ export default { }) this.$refs.form.validate() }, - formatValues(column) { + formatValues (column) { if (column.type === 'set') { if (!column.sets_values || column.sets_values.length === 0) { return @@ -453,47 +473,65 @@ export default { column.enums = column.enums_values.split(',').map(v => v.trim()) } }, - defaultSize(column) { + columnType (column) { const filter = this.columnTypes.filter(t => t.value === column.type) if (!filter || filter.length === 0) { return false } - if (filter[0].defaultSize === undefined || filter[0].defaultSize === null) { - return false - } - return filter[0].defaultSize + return filter[0] }, - defaultD(column) { - const filter = this.columnTypes.filter(t => t.value === column.type) - if (!filter || filter.length === 0) { - return false + sizeHint (column) { + let hint = '' + if (this.columnType(column).size_min !== null) { + hint += `min. ${this.columnType(column).size_min}` } - if (filter[0].defaultD === undefined || filter[0].defaultD === null) { - return false + if (this.columnType(column).size_max) { + if (hint.length > 0) { + hint += ', ' + } + hint += `max. ${this.columnType(column).size_max}` + } + if (!this.columnType(column).size_required) { + hint += ' (optional)' } - return filter[0].defaultD + return hint }, - setDefaultSizeAndD(column) { - column.size = this.defaultSize(column) - column.d = this.defaultD(column) - column.dfid = null - console.debug('for column type', column.type, 'set default size', column.size, '& d', column.d, '& dfid', column.dfid) + dHint (column) { + let hint = '' + if (this.columnType(column).d_min !== null) { + hint += `min. ${this.columnType(column).d_min}` + } + if (this.columnType(column).d_max) { + if (hint.length > 0) { + hint += ', ' + } + hint += `max. ${this.columnType(column).d_max}` + } + if (!this.columnType(column).d_required) { + hint += ' (optional)' + } + return hint }, - hasDate(column) { - return column.type === 'date' || column.type === 'datetime' || column.type === 'timestamp' || column.type === 'time' + setDefaultSizeAndD (column) { + if (this.columnType(column).size_default !== null) { + column.size = this.columnType(column).size_default + } else { + column.size = null + } + if (this.columnType(column).d_default !== null) { + column.d = this.columnType(column).d_default + } else { + column.d = null + } + console.debug('for column type', column.type, 'set default size', column.size, '& d', column.d) + if (column.type === 'serial') { + this.setOthers(column) + } }, - hasEnumOrSet(column) { + hasEnumOrSet (column) { return column.type === 'enum' || column.type === 'set' }, - filterDateFormats(column) { - return this.dateFormats.filter((df) => { - if (column.type === 'date') { - return !df.has_time - } - return df.has_time - }) - }, - sizeErrorMessages(column) { + sizeErrorMessages (column) { if (column.size < column.d) { return ['Size needs to be bigger or equal to d'] } @@ -502,7 +540,7 @@ export default { } return [] }, - dErrorMessages(column) { + dErrorMessages (column) { if (column.size < column.d) { return ['D needs to be smaller or equal to size'] } @@ -511,19 +549,19 @@ export default { } return [] }, - selectOntologyHeader(type, event) { + selectOntologyHeader (type, event) { const analyseService = useAnalyseService() this.headerOntologySelection[type].name = event.guid this.headerOntologySelection[type].suggested = false analyseService.selectOntologyHeader(this.schema_id, type, this.headerOntologySelection, event) }, - updateColumnMatch(column) { + updateColumnMatch (column) { if (!column || !column.name || !column.type) { return } this.updateMatch() }, - updateMatch() { + updateMatch () { this.loadingMatching = true const analyseService = useAnalyseService() analyseService.match(this.schemaName, this.columns) diff --git a/dbrepo-ui/components/table/TableToolbar.vue b/dbrepo-ui/components/table/TableToolbar.vue index ef95ad1bd2eee6406925a956a3dda14950070a7d..1c222cc7c61bd4229c3a8b8e3dd7560a1228eea5 100644 --- a/dbrepo-ui/components/table/TableToolbar.vue +++ b/dbrepo-ui/components/table/TableToolbar.vue @@ -12,8 +12,9 @@ type="subtitle" width="200" /> <span - v-if="table && $vuetify.display.lgAndUp" - v-text="table.name" /> + v-if="table && $vuetify.display.lgAndUp"> + {{ table.name }} + </span> </v-toolbar-title> <v-spacer /> <v-btn diff --git a/dbrepo-ui/components/user/UserBadge.vue b/dbrepo-ui/components/user/UserBadge.vue index 65945725e4954a99cda99696626d0a6d947edfd7..71da03d9290ba16928411adda02f3f9eb99aec16 100644 --- a/dbrepo-ui/components/user/UserBadge.vue +++ b/dbrepo-ui/components/user/UserBadge.vue @@ -8,9 +8,14 @@ <v-badge inline content="you" - color="code">{{ creatorName }}</v-badge> + color="code"> + {{ creatorName }} + </v-badge> + </span> + <span + v-else> + {{ creatorName }} </span> - <span v-else v-text="creatorName" /> </p> </template> diff --git a/dbrepo-ui/composables/access-service.ts b/dbrepo-ui/composables/access-service.ts index c08e5d0b9f6bac53b8d7eaeba993e06234435b31..056efec1171933d7dcf0921c7eff34717d574333 100644 --- a/dbrepo-ui/composables/access-service.ts +++ b/dbrepo-ui/composables/access-service.ts @@ -21,7 +21,7 @@ export const useAccessService = (): any => { const axios = useAxiosInstance() console.debug('create access for user with id', userId, 'of database with id', databaseId) return new Promise<DatabaseAccessDto>((resolve, reject) => { - axios.post<DatabaseAccessDto>(`/api/database/${databaseId}/access`, payload) + axios.post<DatabaseAccessDto>(`/api/database/${databaseId}/access/${userId}`, payload) .then((response) => { console.info('Created access for user with id', userId, 'of database with id', databaseId) resolve(response.data) diff --git a/dbrepo-ui/composables/query-service.ts b/dbrepo-ui/composables/query-service.ts index abcd928b66d0350fd855ae380b959a33818b8f3d..b3c21c605344db722259df375d7eba98404c65de 100644 --- a/dbrepo-ui/composables/query-service.ts +++ b/dbrepo-ui/composables/query-service.ts @@ -126,7 +126,7 @@ export const useQueryService = (): any => { }) } - function build(table: TableDto, columns: ColumnDto[], clauses: any[]): QueryBuildResultDto { + function build(table: TableDto, columns: ColumnDto[], types: DataTypeDto[], clauses: any[]): QueryBuildResultDto { var sql = 'SELECT' for (let i = 0; i < columns.length; i++) { sql += `${i > 0 ? ',' : ''} \`${columns[i].internal_name}\`` @@ -140,8 +140,8 @@ export const useQueryService = (): any => { sql += ` ${clause.type.toUpperCase()} ` continue } - const fCol = columns.filter(c => c.internal_name === clause.params[0]) - if (fCol.length === 0) { + const filteredColumn = columns.filter(c => c.internal_name === clause.params[0]) + if (filteredColumn.length === 0) { return { error: true, reason: 'column.exists', @@ -151,26 +151,26 @@ export const useQueryService = (): any => { } } sql += ` \`${clause.params[0]}\` ${clause.params[1]} ` - const fCon = mySql8DataTypes().filter(t => t.value === fCol[0].column_type) - if (fCol.length === 0) { + const filteredType = types.filter(t => t.value === filteredColumn[0].column_type) + if (filteredType.length === 0) { return { error: true, - reason: 'type.exists', - column: fCol[0].column_type, + reason: 'exists', + column: filteredColumn[0].column_type, raw: null, formatted: null } } - if (!fCon[0].isBuildable) { + if (!filteredType[0].is_buildable) { return { error: true, - reason: 'type.build', - column: fCol[0].column_type, + reason: 'build', + column: filteredColumn[0].column_type, raw: null, formatted: null } } - if (fCon[0].quoted) { + if (filteredType[0].is_quoted) { sql += `'${clause.params[2]}'` } else { sql += `${clause.params[2]}` @@ -196,39 +196,5 @@ export const useQueryService = (): any => { return {timestamp, page, size} } - function mySql8DataTypes(): MySql8DataType[] { - return [ - {value: 'bigint', text: 'BIGINT(size)', defaultSize: 255, defaultD: null, quoted: false, isBuildable: true}, - {value: 'binary', text: 'BINARY(size)', defaultSize: 1, defaultD: null, quoted: false, isBuildable: false}, - {value: 'bit', text: 'BIT(size)', defaultSize: 1, defaultD: null, quoted: false, isBuildable: true}, - {value: 'blob', text: 'BLOB', defaultSize: null, defaultD: null, quoted: false, isBuildable: false}, - {value: 'bool', text: 'BOOL', defaultSize: null, defaultD: null, quoted: false, isBuildable: true}, - {value: 'char', text: 'CHAR(size)', defaultSize: 1, defaultD: null, quoted: true, isBuildable: true}, - {value: 'date', text: 'DATE', defaultSize: null, defaultD: null, quoted: true, isBuildable: true}, - {value: 'datetime', text: 'DATETIME(fsp)', defaultSize: null, defaultD: null, quoted: true, isBuildable: true}, - {value: 'decimal', text: 'DECIMAL(size, d)', defaultSize: 10, defaultD: 4, quoted: false, isBuildable: true}, - {value: 'double', text: 'DOUBLE(size, d)', defaultSize: 25, defaultD: 4, quoted: false, isBuildable: true}, - {value: 'enum', text: 'ENUM(val1,val2,...)', defaultSize: null, defaultD: null, quoted: true, isBuildable: true}, - {value: 'float', text: 'FLOAT(p)', defaultSize: 24, defaultD: null, quoted: false, isBuildable: true}, - {value: 'int', text: 'INT(size)', defaultSize: 255, defaultD: null, quoted: false, isBuildable: true}, - {value: 'longblob', text: 'LONGBLOB', defaultSize: null, defaultD: null, quoted: false, isBuildable: false}, - {value: 'longtext', text: 'LONGTEXT', defaultSize: null, defaultD: null, quoted: true, isBuildable: true}, - {value: 'mediumblob', text: 'MEDIUMBLOB', defaultSize: null, defaultD: null, quoted: false, isBuildable: false}, - {value: 'mediumint', text: 'MEDIUMINT(size)', defaultSize: 10, defaultD: null, quoted: false, isBuildable: true}, - {value: 'mediumtext', text: 'MEDIUMTEXT', defaultSize: null, defaultD: null, quoted: true, isBuildable: true}, - {value: 'set', text: 'SET(val1,val2,...)', defaultSize: null, defaultD: null, quoted: true, isBuildable: true}, - {value: 'smallint', text: 'SMALLINT(size)', defaultSize: 10, defaultD: null, quoted: false, isBuildable: true}, - {value: 'text', text: 'TEXT', defaultSize: null, defaultD: null, quoted: true, isBuildable: true}, - {value: 'time', text: 'TIME(fsp)', defaultSize: null, defaultD: null, quoted: true, isBuildable: true}, - {value: 'timestamp', text: 'TIMESTAMP(fsp)', defaultSize: null, defaultD: null, quoted: true, isBuildable: true}, - {value: 'tinyblob', text: 'TINYBLOB', defaultSize: null, defaultD: null, quoted: false, isBuildable: false}, - {value: 'tinyint', text: 'TINYINT(size)', defaultSize: 10, defaultD: null, quoted: false, isBuildable: true}, - {value: 'tinytext', text: 'TINYTEXT', defaultSize: null, defaultD: null, quoted: true, isBuildable: true}, - {value: 'year', text: 'YEAR', defaultSize: null, defaultD: null, quoted: true, isBuildable: true}, - {value: 'varbinary', text: 'VARBINARY(size)', defaultSize: 1, defaultD: null, quoted: false, isBuildable: false}, - {value: 'varchar', text: 'VARCHAR(size)', defaultSize: 255, defaultD: null, quoted: true, isBuildable: true} - ] - } - - return {findAll, findOne, update, exportCsv, execute, reExecuteData, reExecuteCount, build, mySql8DataTypes} + return {findAll, findOne, update, exportCsv, execute, reExecuteData, reExecuteCount, build} } diff --git a/dbrepo-ui/composables/table-service.ts b/dbrepo-ui/composables/table-service.ts index 52959d33c012e43ff46cd793482b3da674a5dc9e..cb0fc109090176c4334cac01fedf0c8cc4e46ea9 100644 --- a/dbrepo-ui/composables/table-service.ts +++ b/dbrepo-ui/composables/table-service.ts @@ -194,7 +194,6 @@ export const useTableService = (): any => { type: c.type, size: c.size ? c.size : null, d: c.d ? c.d : null, - dfid: c.dfid ? c.dfid : null, enums: c.enums_values ? c.enums_values.split(',') : [], sets: c.sets_values ? c.sets_values.split(',') : [], index_length: c.index_length, diff --git a/dbrepo-ui/composables/user-service.ts b/dbrepo-ui/composables/user-service.ts index 96fa7dfca46748aff7b786a9158c5152611228e5..e68b914e0e5bd5cfc410b82213e18f3eb0fa32ab 100644 --- a/dbrepo-ui/composables/user-service.ts +++ b/dbrepo-ui/composables/user-service.ts @@ -83,9 +83,14 @@ export const useUserService = (): any => { async function obtainToken(username: string, password: string): Promise<KeycloakOpenIdTokenDto> { console.debug('obtain user token for user with username', username) return new Promise<KeycloakOpenIdTokenDto>((resolve, reject) => { - const userStore = useUserStore() const config = useRuntimeConfig() - axios.post<KeycloakOpenIdTokenDto>(`${config.public.api.client}/api/user/token`, {username, password}) + const userStore = useUserStore() + const instance = axios.create({ + timeout: 90_000, + params: {}, + baseURL: config.public.api.client + }) + instance.post<KeycloakOpenIdTokenDto>('/api/user/token', {username, password}) .then((response) => { console.info('Obtained user token') // eslint-disable-next-line camelcase @@ -105,7 +110,12 @@ export const useUserService = (): any => { console.debug('refresh user token') return new Promise<KeycloakOpenIdTokenDto>((resolve, reject) => { const config = useRuntimeConfig() - axios.put<KeycloakOpenIdTokenDto>(`${config.public.api.client}/api/user/token`, {refresh_token: refreshToken}) + const instance = axios.create({ + timeout: 90_000, + params: {}, + baseURL: config.public.api.client + }) + instance.put<KeycloakOpenIdTokenDto>('/api/user/token', {refresh_token: refreshToken}) .then((response) => { console.info('Refreshed user token') const userStore = useUserStore() diff --git a/dbrepo-ui/composables/view-service.ts b/dbrepo-ui/composables/view-service.ts index 642a7c6e51ca7344dae72dd3ee12550c84c893a3..5b3a25a149813ddf30f622fcb3d51fccb31f6730 100644 --- a/dbrepo-ui/composables/view-service.ts +++ b/dbrepo-ui/composables/view-service.ts @@ -1,4 +1,5 @@ import {axiosErrorToApiError} from '@/utils' +import type {AxiosRequestConfig} from "axios"; export const useViewService = (): any => { async function remove(databaseId: number, viewId: number): Promise<void> { @@ -66,5 +67,27 @@ export const useViewService = (): any => { }) } - return {remove, create, reExecuteData, reExecuteCount} + async function exportData(databaseId: number, viewId: number): Promise<QueryResultDto> { + const axios = useAxiosInstance() + const config: AxiosRequestConfig = { + responseType: 'blob', + headers: { + Accept: 'text/csv' + } + } + console.debug('export data for view with id', viewId, 'in database with id', databaseId); + return new Promise<QueryResultDto>((resolve, reject) => { + axios.get<QueryResultDto>(`/api/database/${databaseId}/view/${viewId}/export`, config) + .then((response) => { + console.info('Exported data for view with id', viewId, 'in database with id', databaseId) + resolve(response.data) + }) + .catch((error) => { + console.error('Failed to export data', error) + reject(axiosErrorToApiError(error)) + }) + }) + } + + return {remove, create, reExecuteData, reExecuteCount, exportData} } diff --git a/dbrepo-ui/dto/index.ts b/dbrepo-ui/dto/index.ts index e6cb7ffbe329a3fc65243fe9b0340ab572e6d14f..bb2895dc23a4486f932e566698e31257120927f0 100644 --- a/dbrepo-ui/dto/index.ts +++ b/dbrepo-ui/dto/index.ts @@ -409,7 +409,6 @@ interface ColumnDto { table_id: number; internal_name: string; date_format: ImageDateDto; - auto_generated: boolean; is_primary_key: boolean; index_length: number; length: number; @@ -605,9 +604,6 @@ interface ImportCsv { separator: string; quote: string; skip_lines: number; - false_element: string; - true_element: string; - null_element: string; line_termination: string; } @@ -635,7 +631,6 @@ interface ColumnCreateDto { type: string; size: number | null; d: number | null; - dfid: number | null; enums: string[]; sets: string[]; unit_uri: string | null; @@ -658,7 +653,6 @@ interface InternalColumnDto { type: string; size: number; d: number; - dfid: number; enums: string[]; sets: string[]; unit: EntityDto | null; @@ -744,9 +738,6 @@ interface ImportDto { separator: string; quote: string; skip_lines: number; - false_element: string; - true_element: string; - null_element: string; line_termination: string; } diff --git a/dbrepo-ui/dto/mysql.ts b/dbrepo-ui/dto/mysql.ts index b100da017c241b94d84169d1c4545d9fb800e9fc..c366e43f649c9f3eebd14b5c114164f5c4c9c71c 100644 --- a/dbrepo-ui/dto/mysql.ts +++ b/dbrepo-ui/dto/mysql.ts @@ -1,8 +1,15 @@ -interface MySql8DataType { +interface DataTypeDto { + display_name: string; value: string; - text: string; - defaultSize: number | null; - defaultD: number | null; - quoted: boolean; - isBuildable: boolean; + size_min: number | null; + size_max: number | null; + size_default: number | null; + size_required: number | null; + d_min: number | null; + d_max: number | null; + d_default: number | null; + d_required: number | null; + documentation: string; + is_quoted: boolean; + is_buildable: boolean; } diff --git a/dbrepo-ui/layouts/default.vue b/dbrepo-ui/layouts/default.vue index 41620761c58257affb380be4be741489c8f77ce8..51b936816299f1565b2517fb0b8daeb01fa5af2f 100644 --- a/dbrepo-ui/layouts/default.vue +++ b/dbrepo-ui/layouts/default.vue @@ -17,8 +17,9 @@ <v-list-item class="mt-2"> <v-list-item-title - class="text-h6" - v-text="title" /> + class="text-h6"> + {{ title }} + </v-list-item-title> </v-list-item> <v-list nav> <v-list-item @@ -35,6 +36,11 @@ to="/semantic" prepend-icon="mdi-share-variant" :title="$t('navigation.semantics')" /> + <v-list-item + v-if="canListContainers" + to="/container" + prepend-icon="mdi-database-settings" + :title="$t('navigation.container')" /> </v-list> <template v-slot:append> <v-alert @@ -44,7 +50,7 @@ border="start" tile :type="message.type"> - {{ message.message }}<span v-if="message.link"> — <a :href="message.link" v-text="message.link_text ? message.link_text : message.link" /></span> + {{ message.message }}<span v-if="message.link"> — <a :href="message.link">{{ message.link_text ? message.link_text : message.link }}</a></span> </v-alert> <div class="d-flex pa-2"> <v-spacer /> @@ -216,6 +222,12 @@ export default { } return this.roles.includes('list-ontologies') }, + canListContainers () { + if (!this.roles) { + return false + } + return this.roles.includes('list-containers') + }, logo () { return this.$config.public.logo }, @@ -225,25 +237,21 @@ export default { }, }, watch: { - '$route.params.database_id': { - handler (newId, oldId) { - if (newId === oldId) { + '$route.params': { + handler (newObj, oldObj) { + if (!newObj.database_id) { return } - this.cacheStore.setRouteDatabase(newId) + /* load database and optional access */ + this.cacheStore.setRouteDatabase(newObj.database_id) if (this.user) { - this.userStore.setRouteAccess(newId) + this.userStore.setRouteAccess(newObj.database_id) } - }, - deep: true, - immediate: true - }, - '$route.params.table_id': { - handler (newId, oldId) { - if (newId === oldId) { + if (!newObj.table_id) { return } - this.cacheStore.setRouteTable(this.$route.params.database_id, newId) + /* load table */ + this.cacheStore.setRouteTable(newObj.database_id, newObj.table_id) }, deep: true, immediate: true diff --git a/dbrepo-ui/locales/en-US.json b/dbrepo-ui/locales/en-US.json index 56637d576a6c2af98359c3bcdaaba5ef99830d5e..911f8d7674b80ce12e87d9c44939a4e52d6405bb 100644 --- a/dbrepo-ui/locales/en-US.json +++ b/dbrepo-ui/locales/en-US.json @@ -2,6 +2,7 @@ "navigation": { "information": "Information", "search": "Search", + "container": "Engines", "ontologies": "Ontologies", "logout": "Logout", "login": "Login", @@ -31,7 +32,9 @@ "no": "No", "mine": "(mine)", "loading": "Loading", - "view": "View" + "view": "View", + "modify": "Modify", + "help": "Help" }, "pages": { "identifier": { @@ -332,7 +335,7 @@ "title": "Dataset Structure", "text": "the table schema manually.", "primary": { - "warn": "No primary key column(s) selected. Please select a column that uniquely identifies data entries." + "warn": "No primary key column(s) selected. Please select one or more column(s) that uniquely identify data entries." } }, "dataset": { @@ -403,8 +406,7 @@ }, "summary": { "title": "Summary", - "prefix": "Imported", - "suffix": "rows from dataset" + "text": "Successfully imported dataset" }, "analyse": { "text": "Upload & Analyse" @@ -448,7 +450,7 @@ } }, "schema": { - "title": "System Versioned", + "title": "Schema", "subtitle": "Table Constraints", "bullet": "●", "assign": "Assign", @@ -560,8 +562,9 @@ "subtitle": "Select a timestamp to view the data for this specific time of day", "chart": { "title": "Data Events", + "legend": "Chart legend: green color marks data insertions, red color marks data deletions (=data updates in some cases)", "ylabel": "# Events", - "xlabel": "Timestamp" + "xlabel": "Data Timestamp (UTC)" }, "timestamp": { "label": "Timestamp", @@ -578,7 +581,7 @@ "hint": "Value is a primary key" }, "format": { - "hint": "Value must be in format" + "hint": "Format hint:" }, "required": { "hint": "Required. " @@ -628,10 +631,10 @@ "access": { "title": "Database Access", "subtitle": "Overview on users with their access to the database", - "read": "You can read all contents", - "write-own": "You can write own tables and read all contents", - "write-all": "You can write own tables and read all contents", - "revoke": "Revoke", + "read": "Read all contents", + "write-own": "Read all contents & write own tables", + "write-all": "Read all contents & write all tables", + "revoke": "No access", "action": "Action", "username": { "label": "Username", @@ -640,9 +643,6 @@ "type": { "label": "Access Type", "hint": "Required" - }, - "submit": { - "text": "Modify" } }, "create": { @@ -659,6 +659,9 @@ }, "submit": { "text": "Create" + }, + "utilization": { + "label": "Utilization" } }, "tables": { @@ -1051,10 +1054,13 @@ } }, "container": { - "title": "Container", + "title": "Engines", "name": { "title": "Name" }, + "subtitle": { + "text": "Engine" + }, "internal-name": { "title": "Internal Name" }, @@ -1093,7 +1099,8 @@ }, "container": { "exists": "Container already exists in metadata database", - "missing": "Failed to find container in metadata database" + "missing": "Failed to find container in metadata database", + "quota": "Database quota exceeded in engine" }, "data": { "connection": "Failed to contact data service", @@ -1154,8 +1161,8 @@ "query": { "missing": "Failed to find query in data service", "invalid": "Query is invalid", - "type.exists": "Failed to build query: no such column type", - "type.build": "Failed to build query: currently no query build support for column type", + "exists": "Failed to build query: no such column type", + "build": "Failed to build query: currently no query build support for column type", "column.exists": "Failed to build query: data columns are missing column with name" }, "store": { @@ -1452,6 +1459,9 @@ "pattern": "Invalid URI", "exists": "URI exists" }, + "column": { + "exists": "Column with this name exists" + }, "user": { "pattern": "Only lowercase letters, min. 3 length", "exists": "This username is already taken" diff --git a/dbrepo-ui/nuxt.config.ts b/dbrepo-ui/nuxt.config.ts index 454cadf9090d23f92198c63e033ba7061221a29c..8def4012d992f9f998969ec2b247398706ec5db4 100644 --- a/dbrepo-ui/nuxt.config.ts +++ b/dbrepo-ui/nuxt.config.ts @@ -1,7 +1,8 @@ -import { transformAssetUrls } from 'vite-plugin-vuetify' +import {transformAssetUrls} from 'vite-plugin-vuetify' -const proxy : any = {} +const proxy: any = {} +/* proxies the backend calls, >>NOT<< the frontend calls (clicking) */ if (process.env.NODE_ENV === 'development') { const api = 'http://localhost' proxy['/api'] = api @@ -12,159 +13,153 @@ if (process.env.NODE_ENV === 'development') { '^/pid': '/pid' } } - process.env.NUXT_PUBLIC_API_SERVER = 'http://localhost' + process.env.NUXT_PUBLIC_API_SERVER = api } /** * https://nuxt.com/docs/guide/concepts/rendering#hybrid-rendering */ -const routeRules = { -} +const routeRules = {} export default defineNuxtConfig({ - app: { - head: { - charset: 'utf-8', - viewport: 'width=device-width, initial-scale=1', - meta: [ - { 'http-equiv': 'Content-Security-Policy', content: 'upgrade-insecure-requests' } - ], - htmlAttrs: { - lang: 'en-US' - } - } - }, - - build: { - transpile: ['vuetify'], - }, - - css: [ - 'vuetify/lib/styles/main.sass', - '@mdi/font/css/materialdesignicons.min.css', - '@/assets/globals.css', - '@/assets/overrides.css', - ], - - runtimeConfig: { - public: { - commit: '', - title: 'Database Repository', - logo: '/logo.svg', - icon: '/favicon.ico', - touch: '/apple-touch-icon.png', - version: 'bun-dev', - broker: { - host: 'localhost', - port: { - '5672': false - }, - extra: '' - }, - variant: { - input: { - normal: 'underlined', - contrast: 'outlined', - }, - button: { - normal: 'flat', - contrast: 'outlined', - }, - list: { - normal: '', - contrast: 'flat', - } - }, - api: { - client: 'http://localhost', - server: 'http://gateway-service', - }, - upload: { - client: 'http://localhost/api/upload/files' - }, - database: { - unsupported: '*,AVG,BIT_AND,BIT_OR,BIT_XOR,COUNT,COUNTDISTINCT,GROUP_CONCAT,JSON_ARRAYAGG,JSON_OBJECTAGG,MAX,MIN,STD,STDDEV,STDDEV_POP,STDDEV_SAMP,SUM,VARIANCE,VAR_POP,VAR_SAMP,--', - image: { - width: 200, - height: 200 - }, - extra: '' - }, - pid: { - default: { - publisher: 'Example University' - } - }, - doi: { - enabled: false, - endpoint: 'https://doi.org' - }, - links: { - rabbitmq: { - text: 'RabbitMQ Admin', - href: '/admin/broker/' - }, - keycloak: { - text: 'Keycloak Admin', - href: '/api/auth/' - } - } - } - }, - - routeRules, - - devServer: { - port: 3001 - }, - - modules: [ - '@pinia/nuxt', - '@pinia-plugin-persistedstate/nuxt', - '@nuxtjs/i18n' - ], - - pinia: { - storesDirs: ['./stores/**'], - }, - - piniaPersistedstate: { - storage: 'localStorage' - }, - - i18n: { - lazy: false, - langDir: 'locales', - strategy: 'no_prefix', - defaultLocale: 'de', - locales: [ - { - 'code': 'en', - 'file': 'en-US.json', - 'name': 'English (US)', - 'iso': 'en-US' - }, - { - 'code': 'de', - 'file': 'de-AT.json', - 'name': 'German (AT)', - 'iso': 'de-AT' - } - ] - - }, - - vite: { - server: { - proxy - }, - vue: { - template: { - transformAssetUrls, - }, - }, - }, - - devtools: { enabled: true }, - compatibilityDate: '2024-07-24' + app: { + head: { + charset: 'utf-8', + viewport: 'width=device-width, initial-scale=1', + meta: [ + {'http-equiv': 'Content-Security-Policy', content: 'upgrade-insecure-requests'} + ], + htmlAttrs: { + lang: 'en-US' + } + } + }, + + build: { + transpile: ['vuetify'], + }, + + builder: 'vite', + + css: [ + 'vuetify/lib/styles/main.sass', + '@mdi/font/css/materialdesignicons.min.css', + '@/assets/globals.css', + '@/assets/overrides.css', + ], + + runtimeConfig: { + public: { + commit: '', + title: 'Database Repository', + logo: '/logo.svg', + icon: '/favicon.ico', + touch: '/apple-touch-icon.png', + version: 'bun-dev', + broker: { + host: 'localhost', + port: { + '5672': false + }, + extra: '' + }, + variant: { + input: { + normal: 'underlined', + contrast: 'outlined', + }, + button: { + normal: 'flat', + contrast: 'outlined', + }, + list: { + normal: '', + contrast: 'flat', + } + }, + api: { + client: 'http://localhost', + server: 'http://gateway-service', + }, + upload: { + client: 'http://localhost/api/upload/files', + prefix: '/' + }, + database: { + unsupported: '*,AVG,BIT_AND,BIT_OR,BIT_XOR,COUNT,COUNTDISTINCT,GROUP_CONCAT,JSON_ARRAYAGG,JSON_OBJECTAGG,MAX,MIN,STD,STDDEV,STDDEV_POP,STDDEV_SAMP,SUM,VARIANCE,VAR_POP,VAR_SAMP,--', + image: { + width: 200, + height: 200 + }, + extra: '' + }, + pid: { + default: { + publisher: 'Example University' + } + }, + doi: { + enabled: false, + endpoint: 'https://doi.org' + }, + links: {} + } + }, + + routeRules, + + devServer: { + port: 3001 + }, + + modules: [ + '@artmizu/nuxt-prometheus', + '@nuxtjs/i18n', + '@pinia/nuxt', + '@pinia-plugin-persistedstate/nuxt' + ], + + pinia: { + storesDirs: ['./stores/**'], + }, + + piniaPersistedstate: { + storage: 'localStorage' + }, + + i18n: { + lazy: false, + langDir: 'locales', + strategy: 'no_prefix', + defaultLocale: 'de', + locales: [ + { + 'code': 'en', + 'file': 'en-US.json', + 'name': 'English (US)', + 'iso': 'en-US' + }, + { + 'code': 'de', + 'file': 'de-AT.json', + 'name': 'German (AT)', + 'iso': 'de-AT' + } + ] + + }, + + vite: { + server: { + proxy + }, + vue: { + template: { + transformAssetUrls, + }, + }, + }, + + devtools: {enabled: true}, + compatibilityDate: '2024-07-24' }) diff --git a/dbrepo-ui/package.json b/dbrepo-ui/package.json index 78ff73d9cb4ad06762a2b4d02a249ed13a78b789..5af18adf4d6bd4c58e0e1e89fdf02b8937bb05b3 100644 --- a/dbrepo-ui/package.json +++ b/dbrepo-ui/package.json @@ -11,6 +11,8 @@ "prod": "bun run .output/server/index.mjs" }, "dependencies": { + "@artmizu/nuxt-prometheus": "^2.4.0", + "@date-fns/utc": "^2.1.0", "@fontsource/open-sans": "^5.0.24", "@mdi/font": "^7.4.47", "@nuxtjs/robots": "^3.0.0", @@ -36,7 +38,7 @@ "vue-meta": "^2.4.0", "vue-toast-notification": "^3.1.2", "vue3-ace-editor": "^2.2.4", - "vuetify": "^3.7.0" + "vuetify": "^3.7.2" }, "devDependencies": { "@nuxtjs/i18n": "^8.1.1", diff --git a/dbrepo-ui/pages/container/index.vue b/dbrepo-ui/pages/container/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..360ce1543fdf086d60d568ed066ccca1f7c04537 --- /dev/null +++ b/dbrepo-ui/pages/container/index.vue @@ -0,0 +1,43 @@ +<template> + <div> + <v-toolbar + flat + :title="$t('pages.container.title')"> + </v-toolbar> + <ContainerList + v-cloak + :loading="loading" + :containers="containers" /> + </div> +</template> + +<script> +import ContainerList from '@/components/container/ContainerList.vue' + +export default { + components: { + ContainerList + }, + data () { + return { + loading: true, + dialog: null, + containers: [] + } + }, + computed: { + roles () { + return this.userStore.getRoles + }, + }, + mounted () { + this.loading = true + const containerService = useContainerService(); + containerService.findAll() + .then((containers) => { + this.containers = containers + this.loading = false + }) + } +} +</script> diff --git a/dbrepo-ui/pages/database/[database_id]/info.vue b/dbrepo-ui/pages/database/[database_id]/info.vue index e2b139fe8fd2a2616c7dae56b8383e502bdb95e3..432b14e21a60968048440da6f0084eb535aa06a7 100644 --- a/dbrepo-ui/pages/database/[database_id]/info.vue +++ b/dbrepo-ui/pages/database/[database_id]/info.vue @@ -45,22 +45,30 @@ <v-list-item :title="$t('pages.database.name.title')" density="compact"> - <div v-text="database.name" /> + <div> + {{ database.name }} + </div> </v-list-item> <v-list-item :title="$t('pages.database.internal-name.title')" density="compact"> - <div v-text="database.internal_name" /> + <div> + {{ database.internal_name }} + </div> </v-list-item> <v-list-item :title="$t('pages.database.visibility.title')" density="compact"> - <div v-text="`${database.is_public ? 'Public' : 'Private'}`" /> + <div> + {{ database.is_public ? 'Public' : 'Private' }} + </div> </v-list-item> <v-list-item :title="$t('pages.database.size.title')" density="compact"> - <div v-text="databaseSize" /> + <div> + {{ databaseSize }} + </div> </v-list-item> <v-list-item :title="$t('pages.database.owner.title')" @@ -74,7 +82,9 @@ <v-list-item :title="$t('pages.database.created.title')" density="compact"> - <div v-text="createdUTC" /> + <div> + {{ createdUTC }} + </div> </v-list-item> <v-list-item v-if="access && access.type" @@ -87,9 +97,14 @@ inline :content="databaseExtraInfo" color="secondary"> - <span v-text="accessDescription.text" /> + <span> + {{ accessDescription.text }} + </span> </v-badge> - <span v-else v-text="accessDescription.text" /> + <span + v-else> + {{ accessDescription.text }} + </span> </span> </div> </v-list-item> @@ -97,9 +112,8 @@ v-if="access" :title="$t('pages.database.connection.title')" density="compact"> - <div> - <pre class="pb-1" v-text="jdbcString" /> - </div> + <pre + class="pb-1">{{ jdbcString }}</pre> </v-list-item> <v-list-item v-if="database.contact" @@ -131,29 +145,39 @@ <v-list-item :title="$t('pages.container.name.title')" density="compact"> - <div v-text="container_name" /> + <div> + {{ container_name }} + </div> </v-list-item> <v-list-item :title="$t('pages.container.internal-name.title')" density="compact"> - <div v-text="container_internal_name" /> + <div> + {{ container_internal_name }} + </div> </v-list-item> <v-list-item :title="$t('pages.container.image-name.title')" density="compact"> - <div v-text="image_name" /> + <div> + {{ image_name }} + </div> </v-list-item> <v-list-item :title="$t('pages.container.image-tag.title')" density="compact"> - <div v-text="image_version" /> + <div> + {{ image_version }} + </div> </v-list-item> </v-list> </v-card-text> </v-card> </v-window-item> </v-window> - <v-breadcrumbs :items="items" class="pa-0 mt-2" /> + <v-breadcrumbs + :items="items" + class="pa-0 mt-2" /> </div> </template> diff --git a/dbrepo-ui/pages/database/[database_id]/settings.vue b/dbrepo-ui/pages/database/[database_id]/settings.vue index 09c3d8263bc46bc74eb0fe34b8651e41c6214ccc..c205e8c431dc6851d9b9b21c0dc8adc916d9d7f5 100644 --- a/dbrepo-ui/pages/database/[database_id]/settings.vue +++ b/dbrepo-ui/pages/database/[database_id]/settings.vue @@ -89,15 +89,19 @@ :items="database.accesses" :items-per-page="10"> <template v-slot:item.qualified_name="{ item }"> - <span v-if="item && item.user" v-text="item.user.qualified_name" /> + <span + v-if="item && item.user"> + {{ item.user.qualified_name }} + </span> </template> <template v-slot:item.action="{ item }"> <v-btn v-if="item && item.user && item.user.username !== user.username" size="x-small" variant="flat" + color="warning" :disabled="!canModifyAccess" - :text="$t('pages.database.subpages.access.submit.text')" + :text="$t('navigation.modify')" @click="modifyAccess(item)" /> </template> </v-data-table> @@ -107,7 +111,7 @@ variant="flat" :disabled="!canCreateAccess" color="warning" - :text="$t('pages.database.subpages.access.submit.text')" + :text="$t('navigation.create')" @click="giveAccess" /> </v-card-text> </v-card> @@ -422,7 +426,7 @@ export default { this.$refs.form.validate() }, closeDialog () { - this.reloadDatabase() + this.cacheStore.reloadDatabase() this.editAccessDialog = false }, updateDatabaseVisibility () { @@ -510,11 +514,11 @@ export default { updateDatabaseOwner () { this.loading = true const databaseService = useDatabaseService() - databaseService.updateOwner(this.$route.params.database_id, this.modifyOwner.id) + databaseService.updateOwner(this.$route.params.database_id, { id: this.modifyOwner.id }) .then(() => { const toast = useToastInstance() toast.success(this.$t('success.database.transfer')) - location.reload() + this.$router.push(`/database/${this.$route.params.database_id}/info`) }) .catch(() => { this.loading = false diff --git a/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/data.vue b/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/data.vue index 4902e2c54f243c7a2e4f3df90f3aa16cf7c26753..b063317e074d69d97c99812a74cdd22a5d3feceb 100644 --- a/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/data.vue +++ b/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/data.vue @@ -11,8 +11,9 @@ color="secondary" width="500" /> <span - v-else - v-text="executionUTC" /> + v-else> + {{ executionUTC }} + </span> </v-toolbar-title> <v-spacer /> <v-btn diff --git a/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/info.vue b/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/info.vue index 1d9101fbf240d8d577026e53361f2cedb8f6486e..01620ea35eebf78969c6353b9ccaa0e7e9fdfb05 100644 --- a/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/info.vue +++ b/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/info.vue @@ -52,7 +52,7 @@ <v-list-item :title="$t('pages.subset.query-hash.title')" density="compact"> - <pre v-text="`${$t('pages.subset.query-hash.prefix')}${subset.query_hash}`" /> + <pre>{{ $t('pages.subset.query-hash.prefix') }}{{ subset.query_hash }}</pre> </v-list-item> <v-list-item v-if="executionUTC" @@ -63,7 +63,7 @@ <v-list-item :title="$t('pages.subset.result-hash.title')" density="compact"> - <pre v-text="result_hash" /> + <pre>{{ result_hash }}</pre> </v-list-item> <v-list-item :title="$t('pages.subset.result-rows.title')" @@ -90,8 +90,9 @@ :title="$t('pages.database.name.title')"> <NuxtLink class="text-primary" - :to="`/database/${database.id}`" - v-text="database.internal_name" /> + :to="`/database/${database.id}`"> + {{ database.internal_name }} + </NuxtLink> </v-list-item> </v-list> </v-card-text> diff --git a/dbrepo-ui/pages/database/[database_id]/subset/create.vue b/dbrepo-ui/pages/database/[database_id]/subset/create.vue index 62241db5050a1aebe1924cf6154d585fb1eb85e9..5202bc633626e135e263056fa39b5022676c1575 100644 --- a/dbrepo-ui/pages/database/[database_id]/subset/create.vue +++ b/dbrepo-ui/pages/database/[database_id]/subset/create.vue @@ -1,5 +1,5 @@ <template> - <div v-if="canExecuteQuery"> + <div v-if="canCreateSubset"> <Builder /> <v-breadcrumbs :items="items" class="pa-0 mt-2" /> </div> @@ -8,6 +8,7 @@ <script> import { useUserStore } from '@/stores/user' import Builder from '@/components/subset/Builder.vue' +import {useCacheStore} from "~/stores/cache.js"; export default { components: { @@ -34,6 +35,7 @@ export default { disabled: true } ], + cacheStore: useCacheStore(), userStore: useUserStore() } }, @@ -44,14 +46,26 @@ export default { roles () { return this.userStore.getRoles }, + database () { + return this.cacheStore.getDatabase + }, access () { return this.userStore.getAccess }, - canExecuteQuery () { - if (!this.roles) { + hasReadAccess () { + if (!this.access) { return false } - return this.roles.includes('execute-query') + return this.access.type === 'read' || this.access.type === 'write_all' || this.access.type === 'write_own' + }, + canCreateSubset () { + if (!this.database) { + return false + } + if (this.database.is_public) { + return true + } + return this.hasReadAccess } } } diff --git a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/data.vue b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/data.vue index bcab9b60be8812f270836644e5f521553a22040d..e9173726e96af147ab849aa2fcd4515484c03825 100644 --- a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/data.vue +++ b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/data.vue @@ -50,7 +50,7 @@ :prepend-icon="$vuetify.display.lgAndUp ? 'mdi-update' : null" variant="flat" :text="$t('toolbars.table.data.version')" - class="ml-2" + class="ml-2 mr-2" @click.stop="pick" /> </v-toolbar> <TimeDrift /> @@ -60,8 +60,9 @@ <v-card v-if="error" variant="flat"> - <v-card-text - v-text="$t('error.table.connection')" /> + <v-card-text> + {{ $t('error.table.connection') }} + </v-card-text> </v-card> <v-data-table-server v-if="!error" @@ -75,6 +76,7 @@ :loading="loadingData || loadingCount" :options.sync="options" :footer-props="footerProps" + :items-per-page-options="footerProps.itemsPerPageOptions" @update:options="loadData"> <template v-for="(blobColumn, idx) in blobColumns" @@ -346,6 +348,7 @@ export default { const tableService = useTableService() tableService.exportData(this.$route.params.database_id, this.$route.params.table_id) .then((data) => { + this.downloadLoading = false const url = URL.createObjectURL(data) const link = document.createElement('a') link.href = url diff --git a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/info.vue b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/info.vue index 08b42c0d936c7e034b67e09edbd07203edde12d7..0221c64df232721f3a81b6bf2641ad37ce6fbf32 100644 --- a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/info.vue +++ b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/info.vue @@ -67,9 +67,14 @@ inline color="secondary" :content="brokerExtraInfo"> - <span v-text="accessDescription" /> + <span> + {{ accessDescription }} + </span> </v-badge> - <span v-else v-text="accessDescription" /> + <span + v-else> + {{ accessDescription}} + </span> </span> </v-list-item> </v-list> @@ -87,7 +92,9 @@ dense> <v-list-item :title="$t('pages.table.protocol.title')"> - <span v-text="$t('pages.table.protocol.name')" /> + <span> + {{ $t('pages.table.protocol.name') }} + </span> </v-list-item> <v-list-item :title="$t('pages.table.exchange.title')"> @@ -100,7 +107,7 @@ <v-list-item :title="$t('pages.table.routing-key.title')"> <div v-if="table.routing_key"> - <pre v-text="table.routing_key" /> + <pre>{{ table.routing_key }}</pre> </div> </v-list-item> <v-list-item @@ -113,8 +120,7 @@ :content="port.secure ? $t('pages.table.connection.secure') : $t('pages.table.connection.insecure')" :color="port.secure ? 'success' : ''"> <pre - class="pb-1" - v-text="amqpString(port)" /> + class="pb-1">{{ amqpString(port) }}</pre> </v-badge> </p> </v-list-item> @@ -137,8 +143,9 @@ :title="$t('pages.database.name.title')"> <NuxtLink class="text-primary" - :to="`/database/${database.id}`" - v-text="database.internal_name" /> + :to="`/database/${database.id}`"> + {{ database.internal_name }} + </NuxtLink> </v-list-item> </v-list> </v-card-text> diff --git a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/schema.vue b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/schema.vue index 3a821a730b50c6292f603b67c8b666add18aaa08..65b6034348399844ddc8f195da9f9cc828056efa 100644 --- a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/schema.vue +++ b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/schema.vue @@ -20,15 +20,14 @@ :items="table.columns"> <template v-slot:item.is_null_allowed="{ item }"> <span - v-if="item.is_null_allowed" - v-text="$t('pages.table.subpages.schema.bullet')" /> {{ item.is_null_allowed }} + v-if="item.is_null_allowed"> + {{ $t('pages.table.subpages.schema.bullet') }} + </span> + {{ item.is_null_allowed }} </template> <template v-slot:item.extra="{ item }"> <pre>{{ extra(item) }}</pre> </template> - <template v-slot:item.auto_generated="{ item }"> - <span v-if="item.auto_generated">●</span> {{ item.auto_generated }} - </template> <template v-slot:item.column_concept="{ item }"> <v-btn v-if="canAssignSemanticInformation && !hasConcept(item)" @@ -47,8 +46,9 @@ @click="pick(item, 'concept')" /> <a v-if="!canAssignSemanticInformation && hasConcept(item)" - :href="item.concept.uri" - v-text="item.concept.name ? item.concept.name : item.concept.uri" /> + :href="item.concept.uri"> + {{ item.concept.name ? item.concept.name : item.concept.uri }} + </a> </template> <template v-slot:item.column_unit="{ item }"> <v-btn @@ -68,8 +68,9 @@ @click="pick(item, 'unit')" /> <a v-if="!canAssignSemanticInformation && hasUnit(item)" - :href="item.unit.uri" - v-text="item.unit.name ? item.unit.name : item.unit.uri" /> + :href="item.unit.uri"> + {{ item.unit.name ? item.unit.name : item.unit.uri }} + </a> </template> </v-data-table> </v-card> @@ -84,18 +85,18 @@ <ul> <li v-if="table.constraints.primary_key.length > 0"> <strong>PRIMARY KEY</strong> - (<i v-text="primaryKeysColumns" />) + (<i>{{ primaryKeysColumns }}</i>) </li> <li v-for="(foreignKey, i) in table.constraints.foreign_keys" :key="`fk-${i}`"> - <strong>FOREIGN KEY</strong> <span v-text="foreignKey.name" /> (<i v-text="foreignKeyColumns(foreignKey)" />) <strong>REFERENCES</strong> <a :href="`/database/${database.id}/table/${foreignKey.referenced_table.id}/schema`" v-text="foreignKeyReferencedTable(foreignKey)" /> (<i v-text="foreignKeyReferencedColumns(foreignKey)" />) + <strong>FOREIGN KEY</strong> <span>{{ foreignKey.name }}</span> (<i>{{ foreignKeyColumns(foreignKey) }}</i>) <strong>REFERENCES</strong> <a :href="`/database/${database.id}/table/${foreignKey.referenced_table.id}/schema`">{{ foreignKeyReferencedTable(foreignKey) }}</a> (<i>{{ foreignKeyReferencedColumns(foreignKey) }}</i>) </li> <li v-for="(uniqueConstraint, i) in table.constraints.uniques" :key="`uk-${i}`"> <strong>UNIQUE INDEX</strong> - (<i v-text="uniqueColumns(uniqueConstraint)" />) + (<i>{{ uniqueColumns(uniqueConstraint) }}</i>) </li> <li v-for="(checkConstraint, i) in table.constraints.checks" :key="`uk-${i}`"> <strong>CHECK CONSTRAINT</strong> - (<i v-text="checkConstraint" />) + (<i>{{ checkConstraint }}</i>) </li> </ul> </v-container> @@ -163,7 +164,6 @@ export default { { value: 'column_concept', title: this.$t('pages.table.subpages.schema.concept.title') }, { value: 'column_unit', title: this.$t('pages.table.subpages.schema.unit.title') }, { value: 'is_null_allowed', title: this.$t('pages.table.subpages.schema.nullable.title') }, - { value: 'auto_generated', title: this.$t('pages.table.subpages.schema.sequence.title') }, { value: 'description', title: this.$t('pages.table.subpages.schema.description.title') }, ], dateColumns: [], @@ -217,12 +217,20 @@ export default { }, methods: { extra (column) { - if (['date', 'datetime', 'timestamp', 'time'].includes(column.column_type)) { - return `fsp=${column.date_format.unix_format}` - } else if (column.column_type === 'float') { - return `p=${column.size}` + if (column.column_type === 'float') { + return `precision=${column.size}` } else if (['decimal', 'double'].includes(column.column_type)) { - return `size=${column.size} d=${column.d}` + let extra = '' + if (column.size !== null) { + extra += `size=${column.size}` + } + if (column.d !== null) { + if (extra.length > 0) { + extra += ', ' + } + extra += `d=${column.d}` + } + return extra } else if (column.column_type === 'enum') { return `(${column.enums.join(', ')})` } else if (column.column_type === 'set') { diff --git a/dbrepo-ui/pages/database/[database_id]/table/create/dataset.vue b/dbrepo-ui/pages/database/[database_id]/table/create/dataset.vue index 6824671a4c7a1085a5227883b54d80718b306250..da69048ebfd944fee58f54e89f29d93dbb342834 100644 --- a/dbrepo-ui/pages/database/[database_id]/table/create/dataset.vue +++ b/dbrepo-ui/pages/database/[database_id]/table/create/dataset.vue @@ -22,8 +22,9 @@ color="info"> {{ $t('pages.table.subpages.import.dataset.text') }} <NuxtLink - :href="`/database/${$route.params.database_id}/table/create/schema`" - v-text="$t('pages.table.subpages.import.schema.text')" /> + :href="`/database/${$route.params.database_id}/table/create/schema`"> + {{ $t('pages.table.subpages.import.schema.text') }} + </NuxtLink> </v-alert> </v-col> </v-row> @@ -141,7 +142,9 @@ border="start" color="success"> {{ $t('pages.table.subpages.create.summary.text') }} - <strong v-text="table.internal_name"/> + <strong> + {{ table.internal_name }} + </strong> </v-alert> </v-col> </v-row> @@ -242,9 +245,6 @@ export default { tableImport: { location: null, quote: '"', - false_element: null, - true_element: null, - null_element: '', separator: ',', line_termination: null, skip_lines: 1 @@ -369,9 +369,6 @@ export default { this.tableImport.separator = separator this.tableImport.skip_lines = skip_lines this.tableImport.quote = quote - this.tableImport.null_element = null_element - this.tableImport.true_element = true_element - this.tableImport.false_element = false_element if (filename) { this.step = 4 } diff --git a/dbrepo-ui/pages/database/[database_id]/table/create/schema.vue b/dbrepo-ui/pages/database/[database_id]/table/create/schema.vue index cea98fbd5923ded96e551a692ec5e3b4edbd75f0..ae6976bcb928718841606a3f86c9e45f5b085467 100644 --- a/dbrepo-ui/pages/database/[database_id]/table/create/schema.vue +++ b/dbrepo-ui/pages/database/[database_id]/table/create/schema.vue @@ -20,6 +20,7 @@ <v-stepper-header> <v-stepper-item :title="$t('pages.table.subpages.create.information.title')" + :complete="valid" :value="1" /> </v-stepper-header> <v-stepper-window @@ -117,8 +118,9 @@ <v-col md="8"> <v-alert border="start" - color="success" - v-text="$t('pages.table.subpages.schema.summary.text') + ' ' + table.internal_name" /> + color="success"> + {{ $t('pages.table.subpages.schema.summary.text') + ' ' + table.internal_name }} + </v-alert> </v-col> </v-row> <v-row> @@ -270,13 +272,13 @@ export default { this.cacheStore.reloadDatabase() this.table = table }) - .catch(({code}) => { + .catch(({code, message}) => { this.loading = false const toast = useToastInstance() if (typeof code !== 'string') { return } - toast.error(this.$t(code)) + toast.error(message) }) .finally(() => { this.loading = false diff --git a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/data.vue b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/data.vue index 838ef2f0f1adf0a90f722ffd73d43457a5b92186..60bfe33a13f367ba88349a94a7808567dbde92d3 100644 --- a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/data.vue +++ b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/data.vue @@ -6,11 +6,19 @@ color="secondary" :title="$t('toolbars.database.current')" flat> + <v-btn + v-if="canDownload" + :prepend-icon="$vuetify.display.lgAndUp ? 'mdi-download' : null" + variant="flat" + :loading="downloadLoading" + :text="$t('toolbars.table.data.download')" + class="mr-2" + @click.stop="download" /> <v-btn :prepend-icon="$vuetify.display.lgAndUp ? 'mdi-refresh' : null" variant="flat" :text="$t('toolbars.table.data.refresh')" - class="mb-1 mr-2" + class="mr-2" :loading="loadingData" @click="reload" /> </v-toolbar> @@ -29,7 +37,6 @@ <script> import TimeDrift from '@/components/TimeDrift.vue' import QueryResults from '@/components/subset/Results.vue' -import { useCacheStore } from '@/stores/cache' export default { components: { @@ -39,6 +46,7 @@ export default { data () { return { loadingData: false, + downloadLoading: false, items: [ { title: this.$t('navigation.databases'), @@ -73,6 +81,21 @@ export default { return null } return this.database.views.filter(v => v.id === Number(this.$route.params.view_id))[0] + }, + access () { + return this.userStore.getAccess + }, + canDownload () { + if (!this.view) { + return false + } + if (this.view.is_public) { + return true + } + if (!this.access) { + return false + } + return this.access.type === 'read' || this.access.type === 'write_own' || this.access.type === 'write_all' } }, mounted () { @@ -82,6 +105,31 @@ export default { reload () { this.$refs.queryResults.reExecute(Number(this.$route.params.view_id)) this.$refs.queryResults.reExecuteCount(Number(this.$route.params.view_id)) + }, + download () { + this.downloadLoading = true + const viewService = useViewService() + viewService.exportData(this.$route.params.database_id, this.$route.params.view_id) + .then((data) => { + this.downloadLoading = false + const url = URL.createObjectURL(data) + const link = document.createElement('a') + link.href = url + link.download = 'view.csv' + document.body.appendChild(link) + link.click() + }) + .catch(({code}) => { + this.downloadLoading = false + const toast = useToastInstance() + if (typeof code !== 'string') { + return + } + toast.error(this.$t(code)) + }) + .finally(() => { + this.downloadLoading = false + }) } } } diff --git a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/info.vue b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/info.vue index 3ec97f2bdaec1109edc16f1bedf0ee22b07a1f52..064fa5f3f20f0c9e1be84fc010e215745834d278 100644 --- a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/info.vue +++ b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/info.vue @@ -65,8 +65,9 @@ :title="$t('pages.database.name.title')"> <NuxtLink class="text-primary" - :to="`/database/${database.id}`" - v-text="database.internal_name" /> + :to="`/database/${database.id}`"> + {{ database.internal_name }} + </NuxtLink> </v-list-item> </v-list> </v-card-text> diff --git a/dbrepo-ui/pages/index.vue b/dbrepo-ui/pages/index.vue index 93c48e189938bd75ff9c93c956163de0a18379ca..037f5b9410f316cce4e24ec2a9d45c6d6615a741 100644 --- a/dbrepo-ui/pages/index.vue +++ b/dbrepo-ui/pages/index.vue @@ -11,7 +11,7 @@ prepend-icon="mdi-plus" variant="flat" :text="$t('toolbars.database.create.text')" - color="primary" + color="secondary" @click.stop="dialog = true" /> </v-toolbar> <DatabaseList diff --git a/dbrepo-ui/pages/search.vue b/dbrepo-ui/pages/search.vue index fe427b25efa416f242eac5405cecdfb9cb7379a1..ebe16ecec1c159de639a6c735b8f806dda1da21f 100644 --- a/dbrepo-ui/pages/search.vue +++ b/dbrepo-ui/pages/search.vue @@ -2,17 +2,19 @@ <div> <v-toolbar variant="flat"> - <v-toolbar-title - v-text="header" /> + <v-toolbar-title> + {{ header }} + </v-toolbar-title> <v-spacer /> <v-btn v-if="canCreateDatabase" class="mr-4" prepend-icon="mdi-plus" - :text="$t('toolbars.database.create.text')" - color="primary" + color="secondary" variant="flat" - @click.stop="createDbDialog = true" /> + @click.stop="createDbDialog = true"> + {{ $t('toolbars.database.create.text') }} + </v-btn> </v-toolbar> <v-card rounded="0" @@ -25,7 +27,7 @@ v-if="isDatabaseSearch" :loading="loading" :databases="results" /> - <div v-else> + <div> <v-card v-for="(result, idx) in results" :key="idx" @@ -36,10 +38,16 @@ <v-divider class="mx-4" /> <v-card-title class="text-primary text-decoration-underline"> - <a v-if="link(result)" :href="link(result)">{{ title(result) }}</a> - <span v-else>{{ title(result) }}</span> + <a v-if="link(result)" :href="link(result)"> + {{ title(result) }} + </a> + <span v-else> + {{ title(result) }} + </span> </v-card-title> - <v-card-subtitle v-text="description(result)" /> + <v-card-subtitle> + {{ description(result) }} + </v-card-subtitle> <v-card-text> <div v-if="tags(result).length > 0" @@ -49,8 +57,9 @@ :key="i" size="small" :color="tag.color" - variant="outlined" - v-text="tag.text" /> + variant="outlined"> + {{ tag.text }} + </v-chip> </div> </v-card-text> </v-card> diff --git a/dbrepo-ui/pages/semantic/index.vue b/dbrepo-ui/pages/semantic/index.vue index f6b6721b17c28d1bc5f30d2885ee253139d96a0c..480483aaf83bf68911090c1f7dcdbe051542676d 100644 --- a/dbrepo-ui/pages/semantic/index.vue +++ b/dbrepo-ui/pages/semantic/index.vue @@ -1,7 +1,9 @@ <template> <div v-if="canListOntologies"> <v-toolbar flat> - <v-toolbar-title v-text="$t('pages.semantics.title')" /> + <v-toolbar-title> + {{ $t('pages.semantics.title') }} + </v-toolbar-title> <v-spacer /> <v-btn v-if="canListOntologies" @@ -13,10 +15,12 @@ <v-tabs v-model="tab" color="primary"> - <v-tab - v-text="$t('toolbars.semantic.ontologies.concepts')" /> - <v-tab - v-text="$t('toolbars.semantic.ontologies.units')" /> + <v-tab> + {{ $t('toolbars.semantic.ontologies.concepts') }} + </v-tab> + <v-tab> + {{ $t('toolbars.semantic.ontologies.units') }} + </v-tab> </v-tabs> </template> </v-toolbar> @@ -27,9 +31,13 @@ :items="rows" :options.sync="options" :server-items-length="total" - :footer-props="footerProps"> + :footer-props="footerProps" + :items-per-page-options="footerProps.itemsPerPageOptions"> <template v-slot:item.uri="{ item }"> - <a :href="item.uri" target="_blank" v-text="item.uri" /> + <a :href="item.uri" + target="_blank"> + {{ item.uri }} + </a> </template> <template v-slot:item.action="{ item }"> <v-btn @@ -83,7 +91,7 @@ export default { }, total: -1, footerProps: { - 'items-per-page-options': [10, 20, 30, 40, 50] + itemsPerPageOptions: [10, 25, 50, 100] }, tab: 0, tabs: [ diff --git a/dbrepo-ui/pages/semantic/ontology/_ontology_id/index.vue b/dbrepo-ui/pages/semantic/ontology/_ontology_id/index.vue index 41cfa20426c6d51a12f656ef7cd40bc0dff45405..108ef73e4bfdb6d6f79357c341808dc264302123 100644 --- a/dbrepo-ui/pages/semantic/ontology/_ontology_id/index.vue +++ b/dbrepo-ui/pages/semantic/ontology/_ontology_id/index.vue @@ -1,20 +1,38 @@ <template> - <div v-if="canListOntologies"> + <div + v-if="canListOntologies"> <v-toolbar flat> <v-toolbar-title> - <v-btn id="back-btn" plain class="mr-2" to="/semantic/ontology"> + <v-btn + id="back-btn" + plain + class="mr-2" + to="/semantic/ontology"> <v-icon left>mdi-arrow-left</v-icon> </v-btn> </v-toolbar-title> <v-toolbar-title> - <v-skeleton-loader v-if="loading" type="text" class="skeleton-small" /> + <v-skeleton-loader + v-if="loading" + type="text" + class="skeleton-small" /> <span v-if="!loading"> - Ontology <a v-if="ontology" :href="ontology.uri" target="_blank" v-text="ontology.uri" /> + Ontology + <a + v-if="ontology" + :href="ontology.uri" + target="_blank"> + {{ ontology.uri }} + </a> </span> </v-toolbar-title> <v-spacer /> <v-toolbar-title> - <v-btn v-if="canDeleteOntology" :loading="loadingDelete" color="error" @click="deleteOntology"> + <v-btn + v-if="canDeleteOntology" + :loading="loadingDelete" + color="error" + @click="deleteOntology"> Delete Ontology </v-btn> </v-toolbar-title> diff --git a/dbrepo-ui/pages/semantic/ontology/index.vue b/dbrepo-ui/pages/semantic/ontology/index.vue index c4c5291aefcce046d401c4986fee05a530d897fa..a19b5216c14650cac687b502b2e47706b37ace0a 100644 --- a/dbrepo-ui/pages/semantic/ontology/index.vue +++ b/dbrepo-ui/pages/semantic/ontology/index.vue @@ -6,8 +6,9 @@ size="small" icon="mdi-arrow-left" to="/semantic" /> - <v-toolbar-title - v-text="ontologies.length + ' ' + $t('toolbars.semantic.ontologies.title')" /> + <v-toolbar-title> + {{ ontologies.length + ' ' + $t('toolbars.semantic.ontologies.title') }} + </v-toolbar-title> <v-spacer /> <v-btn v-if="canCreateOntology" diff --git a/dbrepo-ui/plugins/vuetify.ts b/dbrepo-ui/plugins/vuetify.ts index 8f48e315dda516f320283f4b52e262d4e6d6f4ac..e942e529f50cbb6f7eddd9d63080a751006aaa94 100644 --- a/dbrepo-ui/plugins/vuetify.ts +++ b/dbrepo-ui/plugins/vuetify.ts @@ -4,6 +4,7 @@ import colors from 'vuetify/util/colors' import * as components from 'vuetify/components' import * as directives from 'vuetify/directives' import '@mdi/font/css/materialdesignicons.css' +import {rgbParse} from "@kurkle/color"; const tuwThemeLight: ThemeDefinition = { dark: false, diff --git a/dbrepo-ui/stores/cache.js b/dbrepo-ui/stores/cache.js index c733e8d48a4a3d77f4fce9eb9b1558db59d0306e..5004b1beb0170862f5062627656fcf6e8844dd7a 100644 --- a/dbrepo-ui/stores/cache.js +++ b/dbrepo-ui/stores/cache.js @@ -78,6 +78,7 @@ export const useCacheStore = defineStore('cache', { setRouteTable (databaseId, tableId) { if (!databaseId || !tableId) { this.table = null + console.error('Cannot set route table: missing database id', databaseId, 'or table id', tableId) return } const tableService = useTableService() diff --git a/dbrepo-ui/test/test_heap.sh b/dbrepo-ui/test/test_heap.sh new file mode 100755 index 0000000000000000000000000000000000000000..d3ed8722cdc1dacdf4678459a847a1488595fd2b --- /dev/null +++ b/dbrepo-ui/test/test_heap.sh @@ -0,0 +1,10 @@ +#!/bin/bash +CALLS=${CALLS:-1000} +CONCURRENCY=${CONCURRENCY:-10} +ENDPOINT=${ENDPOINT:-http://localhost} + +echo "[DEBUG] Testing endpoint: ${ENDPOINT} x${CALLS} (concurrency ${CONCURRENCY})" +ab -n "${CALLS}" -c "${CONCURRENCY}" "${ENDPOINT}/" +ab -n "${CALLS}" -c "${CONCURRENCY}" "${ENDPOINT}/search" +ab -n "${CALLS}" -c "${CONCURRENCY}" "${ENDPOINT}/login" +ab -n "${CALLS}" -c "${CONCURRENCY}" "${ENDPOINT}/signup" \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 70301a53a348f7c321c569366add1edda1afcdca..58be7c566fc353c741f145be0195e388dc065521 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,13 +7,15 @@ volumes: search-db-data: storage-service-data: identity-service-data: + metric-db-data: + dashboard-service-data: services: dbrepo-metadata-db: restart: "no" container_name: dbrepo-metadata-db hostname: metadata-db - image: docker.io/bitnami/mariadb:11.1.3-debian-11-r6 + image: docker.io/bitnami/mariadb-galera:11.1.3-debian-11-r8 volumes: - metadata-db-data:/bitnami/mariadb - ./dbrepo-metadata-db/1_setup-schema.sql:/docker-entrypoint-initdb.d/1_setup-schema.sql @@ -23,6 +25,7 @@ services: environment: MARIADB_DATABASE: "${METADATA_DB:-dbrepo}" MARIADB_ROOT_PASSWORD: "${METADATA_DB_PASSWORD:-dbrepo}" + MARIADB_GALERA_MARIABACKUP_PASSWORD: "${METADATA_DB_BACKUP_PASSWORD:-dbrepobackup}" healthcheck: test: mysqladmin ping --user=root --password="${METADATA_DB_PASSWORD:-dbrepo}" --silent interval: 10s @@ -35,7 +38,7 @@ services: restart: "no" container_name: dbrepo-data-db hostname: data-db - image: docker.io/bitnami/mariadb:11.1.3-debian-11-r6 + image: docker.io/bitnami/mariadb-galera:11.1.3-debian-11-r8 volumes: - data-db-data:/bitnami/mariadb - "${SHARED_VOLUME:-/tmp}:/tmp" @@ -43,6 +46,7 @@ services: - "3307:3306" environment: MARIADB_ROOT_PASSWORD: "${DATA_DB_PASSWORD:-dbrepo}" + MARIADB_GALERA_MARIABACKUP_PASSWORD: "${DATA_DB_BACKUP_PASSWORD:-dbrepobackup}" healthcheck: test: mysqladmin ping --user=root --password="${DATA_DB_PASSWORD:-dbrepo}" --silent interval: 10s @@ -55,16 +59,18 @@ services: restart: "no" container_name: dbrepo-auth-db hostname: auth-db - image: docker.io/bitnami/mariadb:11.1.3-debian-11-r6 + image: docker.io/bitnami/postgresql:17.0.0-debian-12-r1 volumes: - - auth-db-data:/bitnami/mariadb + - auth-db-data:/bitnami/postgresql ports: - - "3308:3306" + - "5432:5432" environment: - MARIADB_DATABASE: "${AUTH_DB_NAME:-keycloak}" - MARIADB_ROOT_PASSWORD: "${AUTH_DB_PASSWORD:-dbrepo}" + POSTGRESQL_DATABASE: "${AUTH_DB_NAME:-keycloak}" + POSTGRESQL_USERNAME: "${AUTH_DB_USERNAME:-keycloak}" + POSTGRESQL_PASSWORD: "${AUTH_DB_PASSWORD:-dbrepo}" + PGPASSWORD: "${AUTH_DB_PASSWORD:-dbrepo}" healthcheck: - test: mysqladmin ping --user=root --password="${AUTH_DB_PASSWORD:-dbrepo}" --silent + test: "psql -U ${AUTH_DB_USERNAME:-keycloak} -h 127.0.0.1 -p 5432 -d ${AUTH_DB_NAME:-keycloak} -c 'select version();'" interval: 15s timeout: 5s retries: 12 @@ -75,23 +81,26 @@ services: restart: "no" container_name: dbrepo-auth-service hostname: auth-service - image: dbrepo-auth-service:latest + image: bitnami/keycloak:26.0.0-debian-12-r1 + volumes: + - ./dbrepo-auth-service/import-realms.sh:/docker-entrypoint-initdb.d/import-realms.sh + - ./dbrepo-auth-service/master-realm.json:/opt/keycloak/data/import/master-realm.json + - ./dbrepo-auth-service/dbrepo-realm.json:/opt/keycloak/data/import/dbrepo-realm.json ports: - "8080:8080" - build: - context: ./dbrepo-auth-service - network: host + environment: + KEYCLOAK_ENABLE_HTTPS: "false" + KEYCLOAK_ENABLE_STATISTICS: "true" + KEYCLOAK_ENABLE_HEALTH_ENDPOINTS: "true" + KEYCLOAK_DATABASE_HOST: "auth-db" + KEYCLOAK_DATABASE_NAME: "${AUTH_DB_NAME:-keycloak}" + KEYCLOAK_DATABASE_USER: "${AUTH_DB_USERNAME:-keycloak}" + KEYCLOAK_DATABASE_PASSWORD: "${AUTH_DB_PASSWORD:-dbrepo}" healthcheck: - test: curl -sSL 'http://0.0.0.0:8080/realms/dbrepo' | grep "dbrepo" || exit 1 - interval: 15s + test: curl --head -fsS http://localhost:9000/health/ready + interval: 10s timeout: 5s retries: 12 - environment: - AUTH_DB: "${AUTH_DB:-keycloak}" - KC_DB_USERNAME: root - KC_DB_PASSWORD: "${AUTH_DB_PASSWORD:-dbrepo}" - KEYCLOAK_ADMIN: "${AUTH_SERVICE_ADMIN_USERNAME:-admin}" - KEYCLOAK_ADMIN_PASSWORD: "${AUTH_SERVICE_ADMIN_PASSWORD:-admin}" depends_on: dbrepo-identity-service: condition: service_healthy @@ -203,16 +212,19 @@ services: restart: "no" container_name: dbrepo-broker-service hostname: broker-service - image: docker.io/bitnami/rabbitmq:3.12-debian-12 + image: docker.io/bitnami/rabbitmq:3.13.7-debian-12-r4 ports: - 15672:15672 - 5672:5672 + - 1883:1883 volumes: - ./dbrepo-broker-service/rabbitmq.conf:/etc/rabbitmq/rabbitmq.conf - ./dbrepo-broker-service/advanced.config:/etc/rabbitmq/advanced.config - ./dbrepo-broker-service/enabled_plugins:/etc/rabbitmq/enabled_plugins - ./dbrepo-broker-service/definitions.json:/app/definitions.json - broker-service-data:/bitnami/rabbitmq/mnesia + environment: + RABBITMQ_FEATURE_FLAGS: mqtt_v5 depends_on: dbrepo-identity-service: condition: service_healthy @@ -272,6 +284,11 @@ services: OPENSEARCH_USERNAME: ${SEARCH_DB_USERNAME:-admin} OPENSEARCH_PASSWORD: ${SEARCH_DB_PASSWORD:-admin} LOG_LEVEL: ${LOG_LEVEL:-info} + healthcheck: + test: curl -sSL localhost:8080/health | grep 'UP' || exit 1 + interval: 10s + timeout: 5s + retries: 12 dbrepo-data-db-sidecar: restart: "no" @@ -312,14 +329,15 @@ services: network: host environment: NUXT_PUBLIC_API_CLIENT: "${BASE_URL:-http://localhost}" + NUXT_PUBLIC_API_SERVER: "${BASE_URL:-http://localhost}" NUXT_PUBLIC_UPLOAD_CLIENT: "${BASE_URL:-http://localhost}/api/upload/files" depends_on: dbrepo-search-service: - condition: service_started - dbrepo-storage-service: + condition: service_healthy + dbrepo-upload-service: condition: service_healthy healthcheck: - test: wget -qO- localhost:3000 | grep "Database Repository" || exit 1 + test: curl -fsSL http://127.0.0.1:3000 && curl -fsSL http://127.0.0.1:3000/health interval: 10s timeout: 5s retries: 12 @@ -339,8 +357,6 @@ services: depends_on: dbrepo-analyse-service: condition: service_healthy - dbrepo-auth-service: - condition: service_healthy dbrepo-broker-service: condition: service_healthy dbrepo-metadata-service: @@ -352,22 +368,6 @@ services: logging: driver: json-file - # service not part of dbrepo system (but for developing) - dbrepo-search-db-dashboard: - restart: "no" - container_name: dbrepo-search-db-dashboard - hostname: search-db-dashboard - image: docker.io/opensearchproject/opensearch-dashboards:2.10.0 - ports: - - "5601:5601" - volumes: - - ./dbrepo-search-db/opensearch_dashboards.yml:/usr/share/opensearch-dashboards/config/opensearch_dashboards.yml - depends_on: - dbrepo-search-db: - condition: service_healthy - logging: - driver: json-file - dbrepo-identity-service: restart: "no" container_name: dbrepo-identity-service @@ -394,6 +394,7 @@ services: dbrepo-search-service-init: restart: "no" + init: true container_name: dbrepo-search-service-init hostname: search-service-init image: dbrepo-search-service-init:latest @@ -409,6 +410,8 @@ services: depends_on: dbrepo-search-db: condition: service_healthy + dbrepo-metadata-service: + condition: service_healthy logging: driver: json-file @@ -417,12 +420,13 @@ services: container_name: dbrepo-storage-service hostname: storage-service image: docker.io/chrislusf/seaweedfs:3.59 - command: [ "server", "-dir=/data", "-s3", "-s3.port=9000", "-s3.config=/app/s3_config.json", "-metricsPort=9091" ] + command: [ "server", "-dir=/data", "-s3", "-s3.port=9000", "-s3.config=/app/s3_config.json", "-metricsPort=9090" ] volumes: - ./dbrepo-storage-service/s3_config.json:/app/s3_config.json - storage-service-data:/data ports: - "9000:9000" + - "8888:8888" healthcheck: test: echo "cluster.check" | weed shell | grep "checking master.*ok" || exit 1 interval: 10s @@ -431,8 +435,54 @@ services: logging: driver: json-file + dbrepo-metric-db: + restart: "no" + container_name: dbrepo-metric-db + hostname: metric-db + image: bitnami/prometheus:2.54.1-debian-12-r4 + volumes: + - ./dbrepo-metric-db/prometheus.yml:/etc/prometheus/prometheus.yml + - metric-db-data:/opt/bitnami/prometheus/data + ports: + - 9090:9090 + healthcheck: + test: promtool check healthy + interval: 10s + timeout: 5s + retries: 12 + logging: + driver: json-file + + dbrepo-dashboard-service: + restart: "no" + container_name: dbrepo-dashboard-service + hostname: dashboard-service + image: dbrepo-dashboard-service:latest + build: + context: ./dbrepo-dashboard-service + network: host + ports: + - "3000:3000" + volumes: + - dashboard-service-data:/opt/bitnami/grafana/data + environment: + LDAP_ADMIN_USERNAME: "${IDENTITY_SERVICE_ADMIN_USERNAME:-admin}" + LDAP_ADMIN_PASSWORD: "${IDENTITY_SERVICE_ADMIN_PASSWORD:-admin}" + LDAP_ROOT: "${IDENTITY_SERVICE_ROOT:-dc=dbrepo,dc=at}" + healthcheck: + test: test -f /opt/bitnami/grafana/tmp/grafana.pid + interval: 10s + timeout: 5s + retries: 12 + depends_on: + dbrepo-metric-db: + condition: service_started + logging: + driver: json-file + dbrepo-storage-service-init: restart: "no" + init: true container_name: dbrepo-storage-service-init hostname: storage-service-init image: dbrepo-storage-service-init:latest @@ -460,8 +510,8 @@ services: - "-s3-endpoint=${STORAGE_ENDPOINT:-http://storage-service:9000}" - "-s3-bucket=dbrepo" environment: - AWS_ACCESS_KEY_ID: "${STORAGE_USERNAME:-seaweedfsadmin}" - AWS_SECRET_ACCESS_KEY: "${STORAGE_PASSWORD:-seaweedfsadmin}" + AWS_ACCESS_KEY_ID: "${S3_ACCESS_KEY_ID:-seaweedfsadmin}" + AWS_SECRET_ACCESS_KEY: "${S3_SECRET_ACCESS_KEY:-seaweedfsadmin}" AWS_REGION: "${STORAGE_REGION_NAME:-default}" depends_on: dbrepo-storage-service: @@ -487,22 +537,22 @@ services: volumes: - "${SHARED_VOLUME:-/tmp}:/tmp" environment: - AUTH_SERVICE_ADMIN: ${AUTH_SERVICE_ADMIN:-admin} - AUTH_SERVICE_ADMIN_PASSWORD: ${AUTH_SERVICE_ADMIN_PASSWORD:-admin} - AUTH_SERVICE_CLIENT: ${AUTH_SERVICE_CLIENT:-dbrepo-client} - AUTH_SERVICE_CLIENT_SECRET: ${AUTH_SERVICE_CLIENT:-MUwRc7yfXSJwX8AdRMWaQC3Nep1VjwgG} - AUTH_SERVICE_ENDPOINT: ${AUTH_SERVICE_ENDPOINT:-http://auth-service:8080} - BROKER_EXCHANGE_NAME: ${BROKER_EXCHANGE_NAME:-dbrepo} - BROKER_QUEUE_NAME: ${BROKER_QUEUE_NAME:-dbrepo} + AUTH_SERVICE_ADMIN: "${AUTH_SERVICE_ADMIN:-admin}" + AUTH_SERVICE_ADMIN_PASSWORD: "${AUTH_SERVICE_ADMIN_PASSWORD:-admin}" + AUTH_SERVICE_CLIENT: "${AUTH_SERVICE_CLIENT:-dbrepo-client}" + AUTH_SERVICE_CLIENT_SECRET: "${AUTH_SERVICE_CLIENT:-MUwRc7yfXSJwX8AdRMWaQC3Nep1VjwgG}" + AUTH_SERVICE_ENDPOINT: "${AUTH_SERVICE_ENDPOINT:-http://auth-service:8080}" + BROKER_EXCHANGE_NAME: "${BROKER_EXCHANGE_NAME:-dbrepo}" + BROKER_QUEUE_NAME: "${BROKER_QUEUE_NAME:-dbrepo}" BROKER_HOST: "${BROKER_ENDPOINT:-broker-service}" BROKER_PASSWORD: "${SYSTEM_PASSWORD:-admin}" BROKER_PORT: ${BROKER_PORT:-5672} - BROKER_SERVICE_ENDPOINT: ${BROKER_SERVICE_ENDPOINT:-http://gateway-service/admin/broker} + BROKER_SERVICE_ENDPOINT: "${BROKER_SERVICE_ENDPOINT:-http://broker-service:15672}" BROKER_USERNAME: "${SYSTEM_USERNAME:-admin}" BROKER_VIRTUALHOST: "${BROKER_VIRTUALHOST:-dbrepo}" CONNECTION_TIMEOUT: ${CONNECTION_TIMEOUT:-60000} - EXCHANGE_NAME: ${EXCHANGE_NAME:-dbrepo} - METADATA_SERVICE_ENDPOINT: ${METADATA_SERVICE_ENDPOINT:-http://metadata-service:8080} + EXCHANGE_NAME: "${EXCHANGE_NAME:-dbrepo}" + METADATA_SERVICE_ENDPOINT: "${METADATA_SERVICE_ENDPOINT:-http://metadata-service:8080}" GRANT_DEFAULT_READ: "${GRANT_DEFAULT_READ:-SELECT}" GRANT_DEFAULT_WRITE: "${GRANT_DEFAULT_WRITE:-SELECT, CREATE, CREATE VIEW, CREATE ROUTINE, CREATE TEMPORARY TABLES, LOCK TABLES, INDEX, TRIGGER, INSERT, UPDATE, DELETE}" JWT_PUBKEY: "${JWT_PUBKEY:-MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqqnHQ2BWWW9vDNLRCcxD++xZg/16oqMo/c1l+lcFEjjAIJjJp/HqrPYU/U9GvquGE6PbVFtTzW1KcKawOW+FJNOA3CGo8Q1TFEfz43B8rZpKsFbJKvQGVv1Z4HaKPvLUm7iMm8Hv91cLduuoWx6Q3DPe2vg13GKKEZe7UFghF+0T9u8EKzA/XqQ0OiICmsmYPbwvf9N3bCKsB/Y10EYmZRb8IhCoV9mmO5TxgWgiuNeCTtNCv2ePYqL/U0WvyGFW0reasIK8eg3KrAUj8DpyOgPOVBn3lBGf+3KFSYi+0bwZbJZWqbC/Xlk20Go1YfeJPRIt7ImxD27R/lNjgDO/MwIDAQAB}" diff --git a/helm/dbrepo-mariadb-galera/.gitignore b/helm/dbrepo-mariadb-galera/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..613d851d27fbfa390c201b7ed8591da3e04bec35 --- /dev/null +++ b/helm/dbrepo-mariadb-galera/.gitignore @@ -0,0 +1,6 @@ +# generated +*.crt +*.key +*.srl +*.csr +build/* \ No newline at end of file diff --git a/helm/dbrepo-mariadb-galera/.helmignore b/helm/dbrepo-mariadb-galera/.helmignore new file mode 100644 index 0000000000000000000000000000000000000000..b9029e8dea3ccab2aabc5c3a8d9226e9bb9ac827 --- /dev/null +++ b/helm/dbrepo-mariadb-galera/.helmignore @@ -0,0 +1,30 @@ +# Dev +values.dev.yaml +Chart.tpl.yaml +hack/ +# MacOS +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Generated +build/ +artifacthub-repo.yml +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ +# Make +Makefile diff --git a/helm/dbrepo-mariadb-galera/Chart.lock b/helm/dbrepo-mariadb-galera/Chart.lock new file mode 100644 index 0000000000000000000000000000000000000000..fb510b79ee5efe30a1091eb91b09a163f7e6c4e9 --- /dev/null +++ b/helm/dbrepo-mariadb-galera/Chart.lock @@ -0,0 +1,6 @@ +dependencies: +- name: mariadb-galera + repository: https://charts.bitnami.com/bitnami + version: 10.1.3 +digest: sha256:ec9ea7a577993779d520b0c93990fb04847f96e41f2bd503141ba66338340985 +generated: "2024-09-14T01:42:48.297778184+04:00" diff --git a/helm/dbrepo-mariadb-galera/Chart.yaml b/helm/dbrepo-mariadb-galera/Chart.yaml new file mode 100644 index 0000000000000000000000000000000000000000..4be4337885fe446add1835f3a5296bc2a42f9583 --- /dev/null +++ b/helm/dbrepo-mariadb-galera/Chart.yaml @@ -0,0 +1,23 @@ +annotations: + licenses: Apache-2.0 +apiVersion: v2 +name: dbrepo-mariadb-galera +description: Helm Chart for installing DBRepo Data Database +sources: + - https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services +type: application +version: "1.4.6" +appVersion: "1.4.6" +keywords: + - dbrepo +maintainers: + - name: Martin Weise + email: martin.weise@tuwien.ac.at +home: https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/ +icon: https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/raw/master/dbrepo-ui/public/favicon.png +dependencies: + - name: mariadb-galera + alias: database + version: 10.1.3 # app version: 11.1.3 + repository: https://charts.bitnami.com/bitnami + condition: database.enabled \ No newline at end of file diff --git a/helm/dbrepo-mariadb-galera/README.md b/helm/dbrepo-mariadb-galera/README.md new file mode 100644 index 0000000000000000000000000000000000000000..c5aa55100a7959b5a7bc888519e4d7ccbdaefb5e --- /dev/null +++ b/helm/dbrepo-mariadb-galera/README.md @@ -0,0 +1,6 @@ +# DBRepo MariaDB Helm chart + +tbd + +## Parameters + diff --git a/helm/dbrepo-mariadb-galera/charts/mariadb-galera-10.1.3.tgz b/helm/dbrepo-mariadb-galera/charts/mariadb-galera-10.1.3.tgz new file mode 100644 index 0000000000000000000000000000000000000000..c906aaf7634b20f0eaf9358b435b01086bdc4f55 Binary files /dev/null and b/helm/dbrepo-mariadb-galera/charts/mariadb-galera-10.1.3.tgz differ diff --git a/helm/dbrepo-mariadb-galera/templates/_compatibility.tpl b/helm/dbrepo-mariadb-galera/templates/_compatibility.tpl new file mode 100644 index 0000000000000000000000000000000000000000..6fc2aa8fa45e3bf7a8cfdb5312515aa2c27a0491 --- /dev/null +++ b/helm/dbrepo-mariadb-galera/templates/_compatibility.tpl @@ -0,0 +1,42 @@ +{{/* +Copyright Broadcom, Inc. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +{{/* vim: set filetype=mustache: */}} + +{{/* +Return true if the detected platform is Openshift +Usage: +{{- include "common.compatibility.isOpenshift" . -}} +*/}} +{{- define "common.compatibility.isOpenshift" -}} +{{- if .Capabilities.APIVersions.Has "security.openshift.io/v1" -}} +{{- true -}} +{{- end -}} +{{- end -}} + +{{/* +Render a compatible securityContext depending on the platform. By default it is maintained as it is. In other platforms like Openshift we remove default user/group values that do not work out of the box with the restricted-v1 SCC +Usage: +{{- include "common.compatibility.renderSecurityContext" (dict "secContext" .Values.containerSecurityContext "context" $) -}} +*/}} +{{- define "common.compatibility.renderSecurityContext" -}} +{{- $adaptedContext := .secContext -}} + +{{- if (((.context.Values.global).compatibility).openshift) -}} + {{- if or (eq .context.Values.global.compatibility.openshift.adaptSecurityContext "force") (and (eq .context.Values.global.compatibility.openshift.adaptSecurityContext "auto") (include "common.compatibility.isOpenshift" .context)) -}} + {{/* Remove incompatible user/group values that do not work in Openshift out of the box */}} + {{- $adaptedContext = omit $adaptedContext "fsGroup" "runAsUser" "runAsGroup" -}} + {{- if not .secContext.seLinuxOptions -}} + {{/* If it is an empty object, we remove it from the resulting context because it causes validation issues */}} + {{- $adaptedContext = omit $adaptedContext "seLinuxOptions" -}} + {{- end -}} + {{- end -}} +{{- end -}} +{{/* Remove fields that are disregarded when running the container in privileged mode */}} +{{- if $adaptedContext.privileged -}} + {{- $adaptedContext = omit $adaptedContext "capabilities" "seLinuxOptions" -}} +{{- end -}} +{{- omit $adaptedContext "enabled" | toYaml -}} +{{- end -}} \ No newline at end of file diff --git a/helm/dbrepo-mariadb-galera/templates/_helpers.tpl b/helm/dbrepo-mariadb-galera/templates/_helpers.tpl new file mode 100644 index 0000000000000000000000000000000000000000..b17e44d2dfa6f6e7a09c3ab58b35794c46791c71 --- /dev/null +++ b/helm/dbrepo-mariadb-galera/templates/_helpers.tpl @@ -0,0 +1,62 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "kubernetes.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "kubernetes.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "kubernetes.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "kubernetes.labels" -}} +helm.sh/chart: {{ include "kubernetes.chart" . }} +{{ include "kubernetes.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "kubernetes.selectorLabels" -}} +app.kubernetes.io/name: {{ include "kubernetes.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "kubernetes.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "kubernetes.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/helm/dbrepo-mariadb-galera/templates/_names.tpl b/helm/dbrepo-mariadb-galera/templates/_names.tpl new file mode 100644 index 0000000000000000000000000000000000000000..cea9dae390ea083c43da813edeefa5441c007f0e --- /dev/null +++ b/helm/dbrepo-mariadb-galera/templates/_names.tpl @@ -0,0 +1,6 @@ +{{/* +Allow the release namespace to be overridden for multi-namespace deployments in combined charts. +*/}} +{{- define "common.names.namespace" -}} +{{- default .Release.Namespace .Values.namespaceOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} \ No newline at end of file diff --git a/helm/dbrepo-mariadb-galera/templates/configmap.yaml b/helm/dbrepo-mariadb-galera/templates/configmap.yaml new file mode 100644 index 0000000000000000000000000000000000000000..066a0d1afbbc5d46cd00a1f5315195365aef0c66 --- /dev/null +++ b/helm/dbrepo-mariadb-galera/templates/configmap.yaml @@ -0,0 +1,580 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: database-setup + namespace: {{ .Values.namespace }} +data: + {{- with .Values.database.extraInitDbScripts }} + {{ toYaml . | nindent 2 }} + {{- end }} + 02-setup-data.sql: | + BEGIN; + INSERT INTO `mdb_containers` (name, internal_name, image_id, host, port, sidecar_host, sidecar_port, privileged_username, privileged_password) + VALUES ('MariaDB 11.1.3', 'mariadb_11_1_3', 1, 'data-db', 3306, 'data-db', 8080, 'root', 'dbrepo'); + COMMIT; + 01-setup-schema.sql: | + BEGIN; + + CREATE TABLE IF NOT EXISTS `mdb_users` + ( + id character varying(36) NOT NULL, + username character varying(255) NOT NULL, + firstname character varying(255), + lastname character varying(255), + email character varying(255) NOT NULL, + orcid character varying(255), + affiliation character varying(255), + mariadb_password character varying(255) NOT NULL, + theme character varying(255) NOT NULL default ('light'), + language character varying(3) NOT NULL default ('en'), + PRIMARY KEY (id), + UNIQUE (username), + UNIQUE (email) + ) WITH SYSTEM VERSIONING; + + CREATE TABLE IF NOT EXISTS `mdb_images` + ( + id bigint NOT NULL AUTO_INCREMENT, + registry character varying(255) NOT NULL DEFAULT 'docker.io', + name character varying(255) NOT NULL, + version character varying(255) NOT NULL, + default_port integer NOT NULL, + dialect character varying(255) NOT NULL, + driver_class character varying(255) NOT NULL, + jdbc_method character varying(255) NOT NULL, + is_default BOOLEAN NOT NULL DEFAULT FALSE, + created timestamp NOT NULL DEFAULT NOW(), + last_modified timestamp, + PRIMARY KEY (id), + UNIQUE (name, version), + UNIQUE (is_default) + ) WITH SYSTEM VERSIONING; + + CREATE TABLE IF NOT EXISTS `mdb_images_date` + ( + id bigint NOT NULL AUTO_INCREMENT, + iid bigint NOT NULL, + database_format character varying(255) NOT NULL, + unix_format character varying(255) NOT NULL, + example character varying(255) NOT NULL, + has_time boolean NOT NULL, + created_at timestamp NOT NULL DEFAULT NOW(), + PRIMARY KEY (id), + FOREIGN KEY (iid) REFERENCES mdb_images (id), + UNIQUE (database_format, unix_format, example) + ) WITH SYSTEM VERSIONING; + + CREATE TABLE IF NOT EXISTS `mdb_containers` + ( + id bigint NOT NULL AUTO_INCREMENT, + internal_name character varying(255) NOT NULL, + name character varying(255) NOT NULL, + host character varying(255) NOT NULL, + port integer NOT NULL default 3306, + ui_host character varying(255) NOT NULL default host, + ui_port integer NOT NULL default port, + ui_additional_flags text, + sidecar_host character varying(255), + sidecar_port integer, + image_id bigint NOT NULL, + created timestamp NOT NULL DEFAULT NOW(), + last_modified timestamp, + privileged_username character varying(255) NOT NULL, + privileged_password character varying(255) NOT NULL, + quota integer NOT NULL DEFAULT 50, + PRIMARY KEY (id), + FOREIGN KEY (image_id) REFERENCES mdb_images (id) + ) WITH SYSTEM VERSIONING; + + CREATE TABLE IF NOT EXISTS `mdb_data` + ( + ID bigint NOT NULL AUTO_INCREMENT, + PROVENANCE text, + FileEncoding text, + FileType character varying(100), + Version text, + Seperator text, + PRIMARY KEY (ID) + ) WITH SYSTEM VERSIONING; + + CREATE TABLE IF NOT EXISTS `mdb_licenses` + ( + identifier character varying(255) NOT NULL, + uri text NOT NULL, + description text NOT NULL, + PRIMARY KEY (identifier), + UNIQUE (uri(200)) + ) WITH SYSTEM VERSIONING; + + CREATE TABLE IF NOT EXISTS `mdb_databases` + ( + id bigint NOT NULL AUTO_INCREMENT, + cid bigint NOT NULL, + name character varying(255) NOT NULL, + internal_name character varying(255) NOT NULL, + exchange_name character varying(255) NOT NULL, + description text, + engine character varying(20), + is_public boolean NOT NULL DEFAULT TRUE, + image longblob, + created_by character varying(36), + owned_by character varying(36), + contact_person character varying(36), + created timestamp NOT NULL DEFAULT NOW(), + last_modified timestamp, + PRIMARY KEY (id), + FOREIGN KEY (cid) REFERENCES mdb_containers (id) /* currently we only support one-to-one */, + FOREIGN KEY (created_by) REFERENCES mdb_users (id), + FOREIGN KEY (owned_by) REFERENCES mdb_users (id), + FOREIGN KEY (contact_person) REFERENCES mdb_users (id) + ) WITH SYSTEM VERSIONING; + + CREATE TABLE IF NOT EXISTS `mdb_databases_subjects` + ( + dbid BIGINT NOT NULL, + subjects character varying(255) NOT NULL, + PRIMARY KEY (dbid, subjects) + ) WITH SYSTEM VERSIONING; + + CREATE TABLE IF NOT EXISTS `mdb_tables` + ( + ID bigint NOT NULL AUTO_INCREMENT, + tDBID bigint NOT NULL, + tName VARCHAR(64) NOT NULL, + internal_name VARCHAR(64) NOT NULL, + queue_name VARCHAR(255) NOT NULL, + routing_key VARCHAR(255), + tDescription VARCHAR(2048), + num_rows BIGINT, + data_length BIGINT, + max_data_length BIGINT, + avg_row_length BIGINT, + `separator` CHAR(1), + quote CHAR(1), + element_null VARCHAR(50), + skip_lines BIGINT, + element_true VARCHAR(50), + element_false VARCHAR(50), + Version TEXT, + created timestamp NOT NULL DEFAULT NOW(), + versioned boolean not null default true, + created_by character varying(36) NOT NULL, + owned_by character varying(36) NOT NULL, + last_modified timestamp, + PRIMARY KEY (ID), + UNIQUE (tDBID, internal_name), + FOREIGN KEY (tDBID) REFERENCES mdb_databases (id), + FOREIGN KEY (created_by) REFERENCES mdb_users (id), + FOREIGN KEY (owned_by) REFERENCES mdb_users (id) + ) WITH SYSTEM VERSIONING; + + CREATE TABLE IF NOT EXISTS `mdb_columns` + ( + ID BIGINT NOT NULL AUTO_INCREMENT, + tID BIGINT NOT NULL, + dfID BIGINT, + cName VARCHAR(64), + internal_name VARCHAR(64) NOT NULL, + Datatype ENUM ('CHAR','VARCHAR','BINARY','VARBINARY','TINYBLOB','TINYTEXT','TEXT','BLOB','MEDIUMTEXT','MEDIUMBLOB','LONGTEXT','LONGBLOB','ENUM','SET','BIT','TINYINT','BOOL','SMALLINT','MEDIUMINT','INT','BIGINT','FLOAT','DOUBLE','DECIMAL','DATE','DATETIME','TIMESTAMP','TIME','YEAR'), + length BIGINT NULL, + ordinal_position INTEGER NOT NULL, + index_length BIGINT NULL, + description VARCHAR(2048), + size BIGINT, + d BIGINT, + auto_generated BOOLEAN DEFAULT false, + is_null_allowed BOOLEAN NOT NULL DEFAULT true, + val_min NUMERIC NULL, + val_max NUMERIC NULL, + mean NUMERIC NULL, + median NUMERIC NULL, + std_dev Numeric NULL, + created timestamp NOT NULL DEFAULT NOW(), + last_modified timestamp, + FOREIGN KEY (tID) REFERENCES mdb_tables (ID) ON DELETE CASCADE, + PRIMARY KEY (ID) + ) WITH SYSTEM VERSIONING; + + CREATE TABLE IF NOT EXISTS `mdb_columns_enums` + ( + id bigint NOT NULL AUTO_INCREMENT, + column_id bigint NOT NULL, + value CHARACTER VARYING(255) NOT NULL, + FOREIGN KEY (column_id) REFERENCES mdb_columns (ID) ON DELETE CASCADE, + PRIMARY KEY (id) + ) WITH SYSTEM VERSIONING; + + CREATE TABLE IF NOT EXISTS `mdb_columns_sets` + ( + id bigint NOT NULL AUTO_INCREMENT, + column_id bigint NOT NULL, + value CHARACTER VARYING(255) NOT NULL, + FOREIGN KEY (column_id) REFERENCES mdb_columns (ID) ON DELETE CASCADE, + PRIMARY KEY (id) + ) WITH SYSTEM VERSIONING; + + CREATE TABLE IF NOT EXISTS `mdb_columns_nom` + ( + tID bigint, + cID bigint, + maxlength INTEGER, + last_modified timestamp, + created timestamp NOT NULL DEFAULT NOW(), + FOREIGN KEY (tID, cID) REFERENCES mdb_columns (tID, ID), + PRIMARY KEY (tID, cID) + ) WITH SYSTEM VERSIONING; + + CREATE TABLE IF NOT EXISTS `mdb_columns_cat` + ( + tID bigint, + cID bigint, + num_cat INTEGER, + -- cat_array TEXT[], + last_modified timestamp, + created timestamp NOT NULL DEFAULT NOW(), + FOREIGN KEY (tID, cID) REFERENCES mdb_columns (tID, ID), + PRIMARY KEY (tID, cID) + ) WITH SYSTEM VERSIONING; + + CREATE TABLE IF NOT EXISTS `mdb_constraints_foreign_key` + ( + fkid BIGINT NOT NULL AUTO_INCREMENT, + tid BIGINT NOT NULL, + rtid BIGINT NOT NULL, + name VARCHAR(255) NOT NULL, + on_update VARCHAR(50) NULL, + on_delete VARCHAR(50) NULL, + position INT NULL, + PRIMARY KEY (fkid), + FOREIGN KEY (tid) REFERENCES mdb_tables (id) ON DELETE CASCADE, + FOREIGN KEY (rtid) REFERENCES mdb_tables (id) + ) WITH SYSTEM VERSIONING; + + CREATE TABLE IF NOT EXISTS `mdb_constraints_primary_key` + ( + pkid BIGINT NOT NULL AUTO_INCREMENT, + tID BIGINT NOT NULL, + cid BIGINT NOT NULL, + PRIMARY KEY (pkid), + FOREIGN KEY (tID) REFERENCES mdb_tables (id) ON DELETE CASCADE, + FOREIGN KEY (cid) REFERENCES mdb_columns (id) ON DELETE CASCADE + ) WITH SYSTEM VERSIONING; + + CREATE TABLE IF NOT EXISTS `mdb_constraints_foreign_key_reference` + ( + id BIGINT NOT NULL AUTO_INCREMENT, + fkid BIGINT NOT NULL, + cid BIGINT NOT NULL, + rcid BIGINT NOT NULL, + PRIMARY KEY (id), + UNIQUE (fkid, cid, rcid), + FOREIGN KEY (fkid) REFERENCES mdb_constraints_foreign_key (fkid) ON UPDATE CASCADE, + FOREIGN KEY (cid) REFERENCES mdb_columns (id), + FOREIGN KEY (rcid) REFERENCES mdb_columns (id) + ) WITH SYSTEM VERSIONING; + + CREATE TABLE IF NOT EXISTS `mdb_constraints_unique` + ( + uid BIGINT NOT NULL AUTO_INCREMENT, + name VARCHAR(255) NOT NULL, + tid BIGINT NOT NULL, + position INT NULL, + PRIMARY KEY (uid), + FOREIGN KEY (tid) REFERENCES mdb_tables (id) ON DELETE CASCADE + ); + + CREATE TABLE IF NOT EXISTS `mdb_constraints_unique_columns` + ( + id BIGINT NOT NULL AUTO_INCREMENT, + uid BIGINT NOT NULL, + cid BIGINT NOT NULL, + PRIMARY KEY (id), + FOREIGN KEY (uid) REFERENCES mdb_constraints_unique (uid), + FOREIGN KEY (cid) REFERENCES mdb_columns (id) ON DELETE CASCADE + ) WITH SYSTEM VERSIONING; + + CREATE TABLE IF NOT EXISTS `mdb_constraints_checks` + ( + id BIGINT NOT NULL AUTO_INCREMENT, + tid BIGINT NOT NULL, + checks VARCHAR(255) NOT NULL, + PRIMARY KEY (id), + FOREIGN KEY (tid) REFERENCES mdb_tables (id) ON DELETE CASCADE + ) WITH SYSTEM VERSIONING; + + + CREATE TABLE IF NOT EXISTS `mdb_concepts` + ( + id bigint NOT NULL AUTO_INCREMENT, + uri text not null, + name VARCHAR(255) null, + description TEXT null, + created timestamp NOT NULL DEFAULT NOW(), + PRIMARY KEY (id), + UNIQUE (uri(200)) + ) WITH SYSTEM VERSIONING; + + CREATE TABLE IF NOT EXISTS `mdb_units` + ( + id bigint NOT NULL AUTO_INCREMENT, + uri text not null, + name VARCHAR(255) null, + description TEXT null, + created timestamp NOT NULL DEFAULT NOW(), + PRIMARY KEY (id), + UNIQUE (uri(200)) + ) WITH SYSTEM VERSIONING; + + CREATE TABLE IF NOT EXISTS `mdb_columns_concepts` + ( + id bigint NOT NULL, + cID bigint NOT NULL, + created timestamp NOT NULL DEFAULT NOW(), + PRIMARY KEY (id, cid), + FOREIGN KEY (cID) REFERENCES mdb_columns (ID) + ) WITH SYSTEM VERSIONING; + + CREATE TABLE IF NOT EXISTS `mdb_columns_units` + ( + id bigint NOT NULL, + cID bigint NOT NULL, + created timestamp NOT NULL DEFAULT NOW(), + PRIMARY KEY (id, cID), + FOREIGN KEY (cID) REFERENCES mdb_columns (ID) + ) WITH SYSTEM VERSIONING; + + CREATE TABLE IF NOT EXISTS `mdb_view` + ( + id bigint NOT NULL AUTO_INCREMENT, + vdbid bigint NOT NULL, + vName VARCHAR(64) NOT NULL, + internal_name VARCHAR(64) NOT NULL, + Query TEXT NOT NULL, + query_hash VARCHAR(255) NOT NULL, + Public BOOLEAN NOT NULL, + InitialView BOOLEAN NOT NULL, + created timestamp NOT NULL DEFAULT NOW(), + last_modified timestamp, + created_by character varying(36) NOT NULL, + PRIMARY KEY (id), + FOREIGN KEY (vdbid) REFERENCES mdb_databases (id), + FOREIGN KEY (created_by) REFERENCES mdb_users (id) + ) WITH SYSTEM VERSIONING; + + CREATE TABLE IF NOT EXISTS `mdb_banner_messages` + ( + id bigint NOT NULL AUTO_INCREMENT, + type ENUM ('ERROR', 'WARNING', 'INFO') NOT NULL default 'INFO', + message TEXT NOT NULL, + link TEXT NULL, + link_text VARCHAR(255) NULL, + display_start timestamp NULL, + display_end timestamp NULL, + PRIMARY KEY (id) + ) WITH SYSTEM VERSIONING; + + CREATE TABLE IF NOT EXISTS `mdb_ontologies` + ( + id bigint NOT NULL AUTO_INCREMENT, + prefix VARCHAR(8) NOT NULL, + uri TEXT NOT NULL, + uri_pattern TEXT, + sparql_endpoint TEXT NULL, + rdf_path TEXT NULL, + last_modified timestamp, + created timestamp NOT NULL DEFAULT NOW(), + UNIQUE (prefix), + UNIQUE (uri(200)), + PRIMARY KEY (id) + ) WITH SYSTEM VERSIONING; + + CREATE TABLE IF NOT EXISTS `mdb_view_columns` + ( + id BIGINT NOT NULL AUTO_INCREMENT, + view_id BIGINT NOT NULL, + dfID BIGINT, + name VARCHAR(64), + internal_name VARCHAR(64) NOT NULL, + column_type ENUM ('CHAR','VARCHAR','BINARY','VARBINARY','TINYBLOB','TINYTEXT','TEXT','BLOB','MEDIUMTEXT','MEDIUMBLOB','LONGTEXT','LONGBLOB','ENUM','SET','BIT','TINYINT','BOOL','SMALLINT','MEDIUMINT','INT','BIGINT','FLOAT','DOUBLE','DECIMAL','DATE','DATETIME','TIMESTAMP','TIME','YEAR'), + ordinal_position INTEGER NOT NULL, + size BIGINT, + d BIGINT, + auto_generated BOOLEAN DEFAULT false, + is_null_allowed BOOLEAN NOT NULL DEFAULT true, + PRIMARY KEY (id), + FOREIGN KEY (view_id) REFERENCES mdb_view (id) + ) WITH SYSTEM VERSIONING; + + CREATE TABLE IF NOT EXISTS `mdb_identifiers` + ( + id BIGINT NOT NULL AUTO_INCREMENT, + dbid BIGINT NOT NULL, + qid BIGINT, + vid BIGINT, + tid BIGINT, + publisher VARCHAR(255) NOT NULL, + language VARCHAR(2), + publication_year INTEGER NOT NULL, + publication_month INTEGER, + publication_day INTEGER, + identifier_type ENUM ('DATABASE', 'SUBSET', 'VIEW', 'TABLE') NOT NULL, + status ENUM ('DRAFT', 'PUBLISHED') NOT NULL DEFAULT ('PUBLISHED'), + query TEXT, + query_normalized TEXT, + query_hash VARCHAR(255), + execution TIMESTAMP, + result_hash VARCHAR(255), + result_number BIGINT, + doi VARCHAR(255), + created TIMESTAMP NOT NULL DEFAULT NOW(), + created_by VARCHAR(36) NOT NULL, + last_modified TIMESTAMP, + PRIMARY KEY (id), /* must be a single id from persistent identifier concept */ + FOREIGN KEY (dbid) REFERENCES mdb_databases (id), + FOREIGN KEY (created_by) REFERENCES mdb_users (id) + ) WITH SYSTEM VERSIONING; + + CREATE TABLE IF NOT EXISTS `mdb_identifier_licenses` + ( + pid bigint NOT NULL, + license_id VARCHAR(255) NOT NULL, + PRIMARY KEY (pid, license_id), + FOREIGN KEY (pid) REFERENCES mdb_identifiers (id), + FOREIGN KEY (license_id) REFERENCES mdb_licenses (identifier) + ) WITH SYSTEM VERSIONING; + + CREATE TABLE IF NOT EXISTS `mdb_identifier_titles` + ( + id bigint NOT NULL AUTO_INCREMENT, + pid bigint NOT NULL, + title text NOT NULL, + title_type ENUM ('ALTERNATIVE_TITLE', 'SUBTITLE', 'TRANSLATED_TITLE', 'OTHER'), + language VARCHAR(2), + PRIMARY KEY (id), + FOREIGN KEY (pid) REFERENCES mdb_identifiers (id) + ) WITH SYSTEM VERSIONING; + + CREATE TABLE IF NOT EXISTS `mdb_identifier_funders` + ( + id bigint NOT NULL AUTO_INCREMENT, + pid bigint NOT NULL, + funder_name VARCHAR(255) NOT NULL, + funder_identifier TEXT, + funder_identifier_type ENUM ('CROSSREF_FUNDER_ID', 'GRID', 'ISNI', 'ROR', 'OTHER'), + scheme_uri text, + award_number VARCHAR(255), + award_title text, + language VARCHAR(255), + PRIMARY KEY (id), + FOREIGN KEY (pid) REFERENCES mdb_identifiers (id) + ) WITH SYSTEM VERSIONING; + + CREATE TABLE IF NOT EXISTS `mdb_identifier_descriptions` + ( + id bigint NOT NULL AUTO_INCREMENT, + pid bigint NOT NULL, + description text NOT NULL, + description_type ENUM ('ABSTRACT', 'METHODS', 'SERIES_INFORMATION', 'TABLE_OF_CONTENTS', 'TECHNICAL_INFO', 'OTHER'), + language VARCHAR(2), + PRIMARY KEY (id), + FOREIGN KEY (pid) REFERENCES mdb_identifiers (id) + ) WITH SYSTEM VERSIONING; + + CREATE TABLE IF NOT EXISTS `mdb_related_identifiers` + ( + id bigint NOT NULL AUTO_INCREMENT, + pid bigint NOT NULL, + value varchar(255) NOT NULL, + type varchar(255) NOT NULL, + relation varchar(255) NOT NULL, + PRIMARY KEY (id), /* must be a single id from persistent identifier concept */ + FOREIGN KEY (pid) REFERENCES mdb_identifiers (id), + UNIQUE (pid, value) + ) WITH SYSTEM VERSIONING; + + CREATE TABLE IF NOT EXISTS `mdb_identifier_creators` + ( + id bigint NOT NULL AUTO_INCREMENT, + pid bigint NOT NULL, + given_names text, + family_name text, + creator_name VARCHAR(255) NOT NULL, + name_type ENUM ('PERSONAL', 'ORGANIZATIONAL') default 'PERSONAL', + name_identifier text, + name_identifier_scheme ENUM ('ROR', 'GRID', 'ISNI', 'ORCID'), + name_identifier_scheme_uri text, + affiliation VARCHAR(255), + affiliation_identifier text, + affiliation_identifier_scheme ENUM ('ROR', 'GRID', 'ISNI'), + affiliation_identifier_scheme_uri text, + PRIMARY KEY (id), + FOREIGN KEY (pid) REFERENCES mdb_identifiers (id) + ) WITH SYSTEM VERSIONING; + + CREATE TABLE IF NOT EXISTS `mdb_update` + ( + uUserID character varying(255) NOT NULL, + uDBID bigint NOT NULL, + created timestamp NOT NULL DEFAULT NOW(), + PRIMARY KEY (uUserID, uDBID), + FOREIGN KEY (uDBID) REFERENCES mdb_databases (id) + ) WITH SYSTEM VERSIONING; + + CREATE TABLE IF NOT EXISTS `mdb_access` + ( + aUserID character varying(255) NOT NULL, + aDBID bigint REFERENCES mdb_databases (id), + attime TIMESTAMP, + download BOOLEAN, + created timestamp NOT NULL DEFAULT NOW(), + PRIMARY KEY (aUserID, aDBID) + ) WITH SYSTEM VERSIONING; + + CREATE TABLE IF NOT EXISTS `mdb_have_access` + ( + user_id character varying(36) NOT NULL, + database_id bigint REFERENCES mdb_databases (id), + access_type ENUM ('READ', 'WRITE_OWN', 'WRITE_ALL') NOT NULL, + created timestamp NOT NULL DEFAULT NOW(), + PRIMARY KEY (user_id, database_id), + FOREIGN KEY (user_id) REFERENCES mdb_users (id) + ) WITH SYSTEM VERSIONING; + + COMMIT; + BEGIN; + + INSERT INTO `mdb_licenses` (identifier, uri, description) + VALUES ('CC0-1.0', 'https://creativecommons.org/publicdomain/zero/1.0/legalcode', + 'CC0 waives copyright interest in a work you''ve created and dedicates it to the world-wide public domain. Use CC0 to opt out of copyright entirely and ensure your work has the widest reach.'), + ('CC-BY-4.0', 'https://creativecommons.org/licenses/by/4.0/legalcode', + 'The Creative Commons Attribution license allows re-distribution and re-use of a licensed work on the condition that the creator is appropriately credited.'); + + INSERT INTO `mdb_images` (name, registry, version, default_port, dialect, driver_class, jdbc_method) + VALUES ('mariadb', 'docker.io', '11.1.3', 3306, 'org.hibernate.dialect.MariaDBDialect', 'org.mariadb.jdbc.Driver', + 'mariadb'); + + INSERT INTO `mdb_images_date` (iid, database_format, unix_format, example, has_time) + VALUES (1, '%Y-%c-%d %H:%i:%S.%f', 'yyyy-MM-dd HH:mm:ss.SSSSSS', '2022-01-30 13:44:25.499', true), + (1, '%Y-%c-%d %H:%i:%S', 'yyyy-MM-dd HH:mm:ss', '2022-01-30 13:44:25', true), + (1, '%Y-%c-%d', 'yyyy-MM-dd', '2022-01-30', false), + (1, '%H:%i:%S', 'HH:mm:ss', '13:44:25', true), + (1, '%d.%c.%Y', 'dd.MM.yyyy', '30.01.2022', false); + + INSERT INTO `mdb_ontologies` (prefix, uri, uri_pattern, sparql_endpoint, rdf_path) + VALUES ('om', 'http://www.ontology-of-units-of-measure.org/resource/om-2/', + 'http://www.ontology-of-units-of-measure.org/resource/om-2/.*', null, 'rdf/om-2.0.rdf'), + ('wd', 'http://www.wikidata.org/', 'http://www.wikidata.org/entity/.*', 'https://query.wikidata.org/sparql', + null), + ('mo', 'http://purl.org/ontology/mo/', 'http://purl.org/ontology/mo/.*', null, null), + ('dc', 'http://purl.org/dc/elements/1.1/', null, null, null), + ('xsd', 'http://www.w3.org/2001/XMLSchema#', null, null, null), + ('tl', 'http://purl.org/NET/c4dm/timeline.owl#', null, null, null), + ('foaf', 'http://xmlns.com/foaf/0.1/', null, null, null), + ('schema', 'http://schema.org/', null, null, null), + ('rdf', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#', null, null, null), + ('rdfs', 'http://www.w3.org/2000/01/rdf-schema#', null, null, null), + ('owl', 'http://www.w3.org/2002/07/owl#', null, null, null), + ('prov', 'http://www.w3.org/ns/prov#', null, null, null), + ('db', 'http://dbpedia.org', 'http://dbpedia.org/ontology/.*', 'http://dbpedia.org/sparql', null); + COMMIT; + diff --git a/helm/dbrepo-mariadb-galera/templates/secret.yaml b/helm/dbrepo-mariadb-galera/templates/secret.yaml new file mode 100644 index 0000000000000000000000000000000000000000..fc5a2a7c5ddaa757c9fc29dc75b24d787a3c0656 --- /dev/null +++ b/helm/dbrepo-mariadb-galera/templates/secret.yaml @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: Secret +metadata: + name: sidecar-secret + namespace: {{ .Values.namespace }} +stringData: + S3_ACCESS_KEY_ID: "{{ .Values.s3.auth.adminAccessKeyId }}" + S3_SECRET_ACCESS_KEY: "{{ .Values.s3.auth.adminSecretAccessKey }}" + S3_STORAGE_ENDPOINT: "{{ .Values.s3.endpoint }}" diff --git a/helm/dbrepo-mariadb-galera/values.schema.json b/helm/dbrepo-mariadb-galera/values.schema.json new file mode 100644 index 0000000000000000000000000000000000000000..336e7dc1e5fb1f7455ebb7cea7593df6cd016a90 --- /dev/null +++ b/helm/dbrepo-mariadb-galera/values.schema.json @@ -0,0 +1,301 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "properties": { + "database": { + "properties": { + "db": { + "properties": { + "name": { + "type": "string" + } + }, + "type": "object" + }, + "enabled": { + "type": "boolean" + }, + "extraInitDbScripts": { + "properties": {}, + "type": "object" + }, + "extraVolumeMounts": { + "items": { + "properties": { + "mountPath": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "extraVolumes": { + "items": { + "properties": { + "emptyDir": { + "properties": {}, + "type": "object" + }, + "name": { + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "fullnameOverride": { + "type": "string" + }, + "galera": { + "properties": { + "mariabackup": { + "properties": { + "password": { + "type": "string" + }, + "user": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "host": { + "type": "string" + }, + "initdbScriptsConfigMap": { + "type": "string" + }, + "jdbcExtraArgs": { + "type": "string" + }, + "metrics": { + "properties": { + "enabled": { + "type": "boolean" + } + }, + "type": "object" + }, + "persistence": { + "properties": { + "enabled": { + "type": "boolean" + } + }, + "type": "object" + }, + "replicaCount": { + "type": "integer" + }, + "rootUser": { + "properties": { + "password": { + "type": "string" + }, + "user": { + "type": "string" + } + }, + "type": "object" + }, + "service": { + "properties": { + "extraPorts": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "port": { + "type": "integer" + }, + "protocol": { + "type": "string" + }, + "targetPort": { + "type": "integer" + } + }, + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "sidecars": { + "items": { + "properties": { + "envFrom": { + "items": { + "properties": { + "secretRef": { + "properties": { + "name": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "image": { + "type": "string" + }, + "imagePullPolicy": { + "type": "string" + }, + "livenessProbe": { + "properties": { + "exec": { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "initialDelaySeconds": { + "type": "integer" + }, + "periodSeconds": { + "type": "integer" + } + }, + "type": "object" + }, + "name": { + "type": "string" + }, + "ports": { + "items": { + "properties": { + "containerPort": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "protocol": { + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "readinessProbe": { + "properties": { + "exec": { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "initialDelaySeconds": { + "type": "integer" + }, + "periodSeconds": { + "type": "integer" + } + }, + "type": "object" + }, + "securityContext": { + "properties": { + "allowPrivilegeEscalation": { + "type": "boolean" + }, + "capabilities": { + "properties": { + "drop": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "runAsGroup": { + "type": "integer" + }, + "runAsNonRoot": { + "type": "boolean" + }, + "runAsUser": { + "type": "integer" + }, + "seccompProfile": { + "properties": { + "type": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "volumeMounts": { + "items": { + "properties": { + "mountPath": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "s3": { + "properties": { + "auth": { + "properties": { + "adminAccessKeyId": { + "type": "string" + }, + "adminSecretAccessKey": { + "type": "string" + } + }, + "type": "object" + }, + "endpoint": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" +} diff --git a/helm/dbrepo-mariadb-galera/values.yaml b/helm/dbrepo-mariadb-galera/values.yaml new file mode 100644 index 0000000000000000000000000000000000000000..f5026a3b5bdeb9f1ce83e1b4b79cb5e87bef6122 --- /dev/null +++ b/helm/dbrepo-mariadb-galera/values.yaml @@ -0,0 +1,107 @@ +# Copyright the DBRepo developers +# SPDX-License-Identifier: APACHE-2.0 + +## @param namespaceOverride The namespace to install the chart + +s3: + endpoint: http://storage-service-s3:8333 + auth: + adminAccessKeyId: seaweedfsadmin + adminSecretAccessKey: seaweedfsadmin + +database: + ## @param database.enabled Enable the Metadata Database. + enabled: true + ## @skip database.fullnameOverride + fullnameOverride: data-db + ## @param database.host The hostname for the microservices. + host: data-db + rootUser: + ## @param database.rootUser.user The root username. + user: root + ## @param database.rootUser.password The root user password. + password: dbrepo + db: + ## @param database.db.name The database name. + name: dbrepo + galera: + mariabackup: + ## @param database.galera.mariabackup.user The database backup username. + user: backup + ## @param database.galera.mariabackup.password The database backup user password + password: backup + ## @param database.jdbcExtraArgs The extra arguments for JDBC connections in the microservices. + jdbcExtraArgs: "" + metrics: + ## @skip database.metrics.enabled The Prometheus settings. + enabled: false + ## @skip database.initdbScriptsConfigMap The initial database scripts. + initdbScriptsConfigMap: database-setup + ## @param database.extraInitDbScripts Additional init.db scripts that are executed on the first start. + extraInitDbScripts: { } + # 03-additional-data.sql: | + # BEGIN; + # INSERT INTO `mdb_containers` (name, internal_name, image_id, host, port, sidecar_host, sidecar_port, privileged_username, privileged_password) + # VALUES ('MariaDB Galera TEST', 'mariadb_11_1_3', 1, 'data-db', 3306, 'data-db', 80, 'root', 'dbrepo'); + # COMMIT; + ## @param database.replicaCount The number of cluster nodes, should be uneven i.e. 2n+1 + replicaCount: 3 + persistence: + ## @param database.persistence.enabled Enable persistent storage. + enabled: true + ## @skip database.service + service: + extraPorts: + - name: "sidecar" + port: 8080 + targetPort: 8080 + protocol: TCP + ## @skip database.sidecars + sidecars: + - name: sidecar + image: registry.datalab.tuwien.ac.at/dbrepo/data-db-sidecar:1.4.5 + imagePullPolicy: Always + securityContext: + runAsUser: 1001 + runAsGroup: 0 + runAsNonRoot: true + allowPrivilegeEscalation: false + seccompProfile: + type: RuntimeDefault + capabilities: + drop: + - ALL + ports: + - name: "sidecar" + containerPort: 8080 + protocol: TCP + envFrom: + - secretRef: + name: data-service-secret + livenessProbe: + exec: + command: + - /bin/bash + - -ec + - "curl -sSL localhost:8080/health | grep 'UP' || exit 1" + initialDelaySeconds: 120 + periodSeconds: 30 + readinessProbe: + exec: + command: + - /bin/bash + - -ec + - "curl -sSL localhost:8080/health | grep 'UP' || exit 1" + initialDelaySeconds: 30 + periodSeconds: 30 + volumeMounts: + - name: s3 + mountPath: /s3 + ## @skip database.extraVolumeMounts + extraVolumeMounts: + - name: s3 + mountPath: /s3 + ## @skip database.extraVolumes + extraVolumes: + - name: s3 + emptyDir: { } diff --git a/helm/dbrepo/Chart.lock b/helm/dbrepo/Chart.lock index 45878cdfc0597e70b690912b03e500643e617367..0937dd527af328b079b719db542efa264c410368 100644 --- a/helm/dbrepo/Chart.lock +++ b/helm/dbrepo/Chart.lock @@ -5,9 +5,9 @@ dependencies: - name: keycloak repository: https://charts.bitnami.com/bitnami version: 21.6.1 -- name: mariadb - repository: https://charts.bitnami.com/bitnami - version: 14.1.4 +- name: dbrepo-mariadb-galera + repository: file://../dbrepo-mariadb-galera + version: 1.4.7 - name: mariadb-galera repository: https://charts.bitnami.com/bitnami version: 10.1.3 @@ -23,5 +23,11 @@ dependencies: - name: openldap-stack-ha repository: https://jp-gouin.github.io/helm-openldap/ version: 4.2.5 -digest: sha256:bc81f32931159cbea98f6da5f58ff3425a5cd03183506ab218120be136486468 -generated: "2024-07-12T06:33:37.323435643+02:00" +- name: grafana + repository: https://charts.bitnami.com/bitnami + version: 10.1.1 +- name: prometheus + repository: https://charts.bitnami.com/bitnami + version: 1.3.22 +digest: sha256:840d2ea4b1e36fe8fa399fc4170b6274a3de161c13a4a1a3b18ce3107ab71f79 +generated: "2024-10-01T07:48:55.174297756+02:00" diff --git a/helm/dbrepo/Chart.yaml b/helm/dbrepo/Chart.yaml index f32287b93cd1ba982cef7af817c95a70f0af7604..9e09e7f8e37033cc9c8ff2fa4f1776f43212c59c 100644 --- a/helm/dbrepo/Chart.yaml +++ b/helm/dbrepo/Chart.yaml @@ -6,8 +6,8 @@ description: Helm Chart for installing DBRepo sources: - https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services type: application -version: "1.4.5" -appVersion: "1.4.5" +version: "1.4.7" +appVersion: "1.4.7" keywords: - dbrepo maintainers: @@ -26,10 +26,10 @@ dependencies: version: 21.6.1 # app version: 24.0.5 repository: https://charts.bitnami.com/bitnami condition: authservice.enabled - - name: mariadb + - name: dbrepo-mariadb-galera alias: datadb - version: 14.1.4 # app version: 11.1.3 - repository: https://charts.bitnami.com/bitnami + version: 1.4.7 + repository: file://../dbrepo-mariadb-galera condition: datadb.enabled - name: mariadb-galera alias: metadatadb @@ -55,4 +55,14 @@ dependencies: alias: identityservice version: 4.2.5 repository: https://jp-gouin.github.io/helm-openldap/ - condition: identityservice.enabled \ No newline at end of file + condition: identityservice.enabled + - name: grafana + alias: dashboardservice + version: 10.1.1 + repository: https://charts.bitnami.com/bitnami + condition: dashboardservice.enabled + - name: prometheus + alias: metricdb + version: 1.3.22 + repository: https://charts.bitnami.com/bitnami + condition: metricdb.enabled \ No newline at end of file diff --git a/helm/dbrepo/README.md b/helm/dbrepo/README.md index 294fda6477f278e1cc6bf71e0002ca7cfbfc9916..8c479003df6c435f27bc999d2c181bdd2daa11b1 100644 --- a/helm/dbrepo/README.md +++ b/helm/dbrepo/README.md @@ -1,16 +1,17 @@ # DBRepo Helm chart -[DBRepo](https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.4.4/) is a database repository system that +[DBRepo](https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.4.7/) is a database repository system that allows researchers to ingest data into a central, versioned repository through common interfaces. ## TL;DR Download the -sample [`values.yaml`](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/raw/release-1.4.4/helm-charts/dbrepo/values.yaml?inline=true) +sample [ +`values.yaml`](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/raw/release-1.4.7/helm-charts/dbrepo/values.yaml?inline=true) for your deployment and update the variables, especially `hostname`. ```bash -helm install my-release "oci://registry.datalab.tuwien.ac.at/dbrepo/helm" --values ./values.yaml --version "1.4.4" +helm install my-release "oci://registry.datalab.tuwien.ac.at/dbrepo/helm/dbrepo" --values ./values.yaml --version "1.4.7" ``` ## Prerequisites @@ -27,7 +28,7 @@ helm install my-release "oci://registry.datalab.tuwien.ac.at/dbrepo/helm" --valu To install the chart with the release name `my-release`: ```bash -helm install my-release "oci://oci://registry.datalab.tuwien.ac.at/dbrepo/helm" --values ./values.yaml --version "1.4.4" +helm install my-release "oci://oci://registry.datalab.tuwien.ac.at/dbrepo/helm" --values ./values.yaml --version "1.4.7" ``` The command deploys DBRepo on the Kubernetes cluster in the default configuration. The Parameters section lists the @@ -48,24 +49,23 @@ The command removes all the Kubernetes components associated with the chart and ### Global parameters | Name | Description | Value | -| ----------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------ | +|-------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------| | `global.compatibility.openshift.adaptSecurityContext` | Adapt the securityContext sections of the deployment to make them compatible with Openshift restricted-v2 SCC: remove runAsUser, runAsGroup and fsGroup and let the platform use their allowed default IDs. Possible values: auto (apply if the detected running cluster is Openshift), force (perform the adaptation always), disabled (do not perform adaptation) | `auto` | | `global.storageClass` | Global StorageClass for Persistent Volume(s) | `""` | ### Common parameters -| Name | Description | Value | -| --------------- | ---------------------------------- | --------------------- | -| `namespace` | The namespace to install the chart | `dbrepo` | -| `hostname` | The hostname. | `example.com` | -| `gateway` | The gateway endpoint. | `https://example.com` | -| `strategyType` | The image pull | `RollingUpdate` | -| `clusterDomain` | The cluster domain. | `cluster.local` | +| Name | Description | Value | +|-----------------|-----------------------|-----------------------| +| `hostname` | The hostname. | `example.com` | +| `gateway` | The gateway endpoint. | `https://example.com` | +| `strategyType` | The image pull | `RollingUpdate` | +| `clusterDomain` | The cluster domain. | `cluster.local` | ### Metadata Database | Name | Description | Value | -| ---------------------------------------- | ---------------------------------------------------------------- | ------------- | +|------------------------------------------|------------------------------------------------------------------|---------------| | `metadatadb.enabled` | Enable the Metadata Database. | `true` | | `metadatadb.host` | The hostname for the microservices. | `metadata-db` | | `metadatadb.rootUser.user` | The root username. | `root` | @@ -74,32 +74,29 @@ The command removes all the Kubernetes components associated with the chart and | `metadatadb.galera.mariabackup.user` | The database backup username. | `backup` | | `metadatadb.galera.mariabackup.password` | The database backup user password | `backup` | | `metadatadb.jdbcExtraArgs` | The extra arguments for JDBC connections in the microservices. | `""` | -| `metadatadb.initdbScripts` | Additional init.db scripts that are executed on the first start. | `{}` | +| `metadatadb.extraInitDbScripts` | Additional init.db scripts that are executed on the first start. | `{}` | | `metadatadb.replicaCount` | The number of cluster nodes, should be uneven i.e. 2n+1 | `3` | | `metadatadb.persistence.enabled` | Enable persistent storage. | `true` | ### Auth Service | Name | Description | Value | -| -------------------------------- | ------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +|----------------------------------|--------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `authservice.enabled` | Enable the Auth Service. | `true` | | `authservice.image.debug` | Set the logging level to `trace`. Otherwise, set to `info`. | `false` | | `authservice.endpoint` | The hostname for the microservices. | `http://auth-service` | -| `authservice.auth.adminUser` | The admin username. | `fda` | -| `authservice.auth.adminPassword` | The admin user password. | `fda` | | `authservice.jwt.pubkey` | The JWT public key from the `dbrepo-client`. | `MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqqnHQ2BWWW9vDNLRCcxD++xZg/16oqMo/c1l+lcFEjjAIJjJp/HqrPYU/U9GvquGE6PbVFtTzW1KcKawOW+FJNOA3CGo8Q1TFEfz43B8rZpKsFbJKvQGVv1Z4HaKPvLUm7iMm8Hv91cLduuoWx6Q3DPe2vg13GKKEZe7UFghF+0T9u8EKzA/XqQ0OiICmsmYPbwvf9N3bCKsB/Y10EYmZRb8IhCoV9mmO5TxgWgiuNeCTtNCv2ePYqL/U0WvyGFW0reasIK8eg3KrAUj8DpyOgPOVBn3lBGf+3KFSYi+0bwZbJZWqbC/Xlk20Go1YfeJPRIt7ImxD27R/lNjgDO/MwIDAQAB` | | `authservice.tls.enabled` | Enable TLS/SSL communication. Required for HTTPS. | `true` | | `authservice.tls.existingSecret` | The secret containing the `tls.crt`, `tls.key` and `ca.crt`. | `ingress-cert` | -| `authservice.metrics.enabled` | Enable the Prometheus metrics export sidecar container. | `false` | | `authservice.client.id` | The client id for the microservices. | `dbrepo-client` | | `authservice.client.secret` | The client secret for the microservices. | `MUwRc7yfXSJwX8AdRMWaQC3Nep1VjwgG` | ### Data Database | Name | Description | Value | -| --------------------------------- | ----------------------------------------------------------- | ------------- | +|-----------------------------------|-------------------------------------------------------------|---------------| | `datadb.enabled` | Enable the Data Database. | `true` | -| `datadb.image.debug` | Set the logging level to `trace`. Otherwise, set to `info`. | `false` | +| `datadb.database.image.debug` | Set the logging level to `trace`. Otherwise, set to `info`. | `false` | | `datadb.auth.rootPassword` | The root user password. | `dbrepo` | | `datadb.auth.replicationUser` | The database replication user password | `replication` | | `datadb.auth.replicationPassword` | The database replication user password | `replication` | @@ -107,7 +104,7 @@ The command removes all the Kubernetes components associated with the chart and ### Search Database | Name | Description | Value | -| ---------------------- | ----------------------------------- | ----------- | +|------------------------|-------------------------------------|-------------| | `searchdb.enabled` | Enable the Data Database. | `true` | | `searchdb.host` | The hostname for the microservices. | `search-db` | | `searchdb.port` | The port for the microservices. | `9200` | @@ -116,14 +113,14 @@ The command removes all the Kubernetes components associated with the chart and ### Upload Service | Name | Description | Value | -| ---------------------------- | -------------------------- | ------ | +|------------------------------|----------------------------|--------| | `uploadservice.enabled` | Enable the Upload Service. | `true` | | `uploadservice.replicaCount` | The number of replicas. | `2` | ### Broker Service | Name | Description | Value | -| ----------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- | +|-------------------------------------|----------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------| | `brokerservice.enabled` | Enable the Broker Service. | `true` | | `brokerservice.image.debug` | Set the logging level to `trace`. Otherwise, set to `info`. | `true` | | `brokerservice.endpoint` | The management api endpoint for the microservices. | `http://broker-service:15672` | @@ -137,7 +134,7 @@ The command removes all the Kubernetes components associated with the chart and | `brokerservice.ldap.binddn` | The domain name the broker service should bind to. In many cases this is the admin user from `identityservice.global.adminUser`. | `cn=admin,dc=dbrepo,dc=at` | | `brokerservice.ldap.bindpw` | The password to bind on the identity service. In many cases this value is equal to `identityservice.global.adminPassword`. | `admin` | | `brokerservice.ldap.uidField` | The field containing the user id. | `uid` | -| `brokerservice.ldap.basedn` | The base domain name containing the users. | `ou=users,dc=dbrepo,dc=at` | +| `brokerservice.ldap.basedn` | The base domain name containing the users. | `dc=dbrepo,dc=at` | | `brokerservice.ldap.userDnPattern` | The pattern to determine the user. | `${username}` | | `brokerservice.extraPlugins` | The list of plugins to be activated. | `rabbitmq_prometheus rabbitmq_auth_backend_ldap rabbitmq_auth_mechanism_ssl` | | `brokerservice.persistence.enabled` | If set to true, a PVC will be created. | `false` | @@ -146,7 +143,7 @@ The command removes all the Kubernetes components associated with the chart and ### Analyse Service | Name | Description | Value | -| ------------------------------------------------------------------ | ----------------------------------------------------------- | -------------------------------- | +|--------------------------------------------------------------------|-------------------------------------------------------------|----------------------------------| | `analyseservice.enabled` | Enable the Broker Service. | `true` | | `analyseservice.image.debug` | Set the logging level to `trace`. Otherwise, set to `info`. | `false` | | `analyseservice.podSecurityContext.enabled` | Enable pods' Security Context | `true` | @@ -170,7 +167,7 @@ The command removes all the Kubernetes components associated with the chart and ### Metadata Service | Name | Description | Value | -| ------------------------------------------------------------------- | ---------------------------------------------------------------------------------- | -------------------------------- | +|---------------------------------------------------------------------|------------------------------------------------------------------------------------|----------------------------------| | `metadataservice.enabled` | Enable the Broker Service. | `true` | | `metadataservice.image.debug` | Set the logging level to `trace`. Otherwise, set to `info`. | `false` | | `metadataservice.podSecurityContext.enabled` | Enable pods' Security Context | `true` | @@ -178,7 +175,7 @@ The command removes all the Kubernetes components associated with the chart and | `metadataservice.podSecurityContext.sysctls` | Set kernel settings using the sysctl interface | `[]` | | `metadataservice.podSecurityContext.supplementalGroups` | Set filesystem extra groups | `[]` | | `metadataservice.podSecurityContext.fsGroup` | Set RabbitMQ pod's Security Context fsGroup | `1001` | -| `metadataservice.containerSecurityContext.enabled` | Enabled containers' Security Context | `true` | +| `metadataservice.containerSecurityContext.enabled` | Enable containers' Security Context | `true` | | `metadataservice.containerSecurityContext.seLinuxOptions` | Set SELinux options in container | `{}` | | `metadataservice.containerSecurityContext.runAsUser` | Set RabbitMQ containers' Security Context runAsUser | `1001` | | `metadataservice.containerSecurityContext.runAsGroup` | Set RabbitMQ containers' Security Context runAsGroup | `1001` | @@ -208,7 +205,7 @@ The command removes all the Kubernetes components associated with the chart and ### Data Service | Name | Description | Value | -| --------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------- | +|-----------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------| | `dataservice.enabled` | Enable the Broker Service. | `true` | | `dataservice.endpoint` | Absolute URL to the data service in the form of http://host:port | `http://data-service` | | `dataservice.image.debug` | Set the logging level to `trace`. Otherwise, set to `info`. | `false` | @@ -246,7 +243,7 @@ The command removes all the Kubernetes components associated with the chart and ### Search Service | Name | Description | Value | -| ----------------------------------------------------------------- | ------------------------------------------------------------------ | ----------------------- | +|-------------------------------------------------------------------|--------------------------------------------------------------------|-------------------------| | `searchservice.enabled` | Enable the Broker Service. | `true` | | `searchservice.endpoint` | Absolute URL to the search service in the form of http://host:port | `http://search-service` | | `searchservice.image.debug` | Set the logging level to `trace`. Otherwise, set to `info`. | `false` | @@ -269,8 +266,9 @@ The command removes all the Kubernetes components associated with the chart and ### Storage Service | Name | Description | Value | -| --------------------------------------------- | -------------------------------------------------------------------------------------- | ---------------- | +|-----------------------------------------------|----------------------------------------------------------------------------------------|------------------| | `storageservice.enabled` | Enable the Storage Service. | `true` | +| `storageservice.mariadb.auth.rootPassword` | The user password for the root user. | `seaweedfsdb` | | `storageservice.filer.enabled` | Enable the storage service filer which is required for S3. | `true` | | `storageservice.s3.replicaCount` | The number of replicas. | `2` | | `storageservice.s3.bucket` | The S3-bucket name. | `dbrepo` | @@ -281,7 +279,7 @@ The command removes all the Kubernetes components associated with the chart and ### Identity Service | Name | Description | Value | -| -------------------------------------- | ------------------------------------------------------------------------------------------------------------- | ----------------- | +|----------------------------------------|---------------------------------------------------------------------------------------------------------------|-------------------| | `identityservice.enabled` | Enable the Identity Service. | `true` | | `identityservice.global.ldapDomain` | The LDAP domain name in domain "dbrepo.at" form or explicit in "dc=dbrepo,dc=at" form. | `dc=dbrepo,dc=at` | | `identityservice.global.adminUser` | The admin username that is used to bind. | `admin` | @@ -296,7 +294,7 @@ The command removes all the Kubernetes components associated with the chart and ### User Interface | Name | Description | Value | -| ------------------------------------------------------ | ---------------------------------------------------------------------------------------------------- | ----------------------- | +|--------------------------------------------------------|------------------------------------------------------------------------------------------------------|-------------------------| | `ui.enabled` | Enable the Broker Service. | `true` | | `ui.image.debug` | Set the logging level to `trace`. Otherwise, set to `info`. | `false` | | `ui.podSecurityContext.enabled` | Enable pods' Security Context | `true` | @@ -321,19 +319,32 @@ The command removes all the Kubernetes components associated with the chart and | `ui.public.icon` | The user interface icon. | `/favicon.ico` | | `ui.public.touch` | The user interface apple touch icon. | `/apple-touch-icon.png` | | `ui.public.broker.host` | The displayed broker hostname. | `example.com` | -| `ui.public.broker.port.5671` | Enable display of the broker 5671 port and mark it as secure (SSL/TLS). | `true` | -| `ui.public.broker.port.5672` | Enable display of the broker 5672 port and mark it as insecure (no SSL/TLS). | `false` | +| `ui.public.broker.port.5671` | Enable display of the broker 5671 port and mark it as secure (SSL/TLS). | `false` | +| `ui.public.broker.port.5672` | Enable display of the broker 5672 port and mark it as insecure (no SSL/TLS). | `true` | | `ui.public.broker.extra` | Extra metadata displayed. | `""` | -| `ui.public.database.extra` | Extra metadata displayed. | `128.130.0.0/15` | +| `ui.public.database.extra` | Extra metadata displayed. | `""` | | `ui.public.pid.default.publisher` | The default dataset publisher for persisted identifiers. | `Example University` | | `ui.public.doi.enabled` | Enable the display that DOIs are minted. | `false` | | `ui.public.doi.endpoint` | The DOI proxy. | `https://doi.org` | | `ui.replicaCount` | The number of replicas. | `2` | +### Dashboard Service + +| Name | Description | Value | +|-----------------------------------------------|------------------------------------------------------------------------------------------------------------------------|--------| +| `dashboardservice.enabled` | Enable the Dashboard Service. | `true` | +| `dashboardservice.dashboardsProvider.enabled` | Enable the default dashboard provisioning provider to routinely import dashboards from /opt/bitnami/grafana/dashboards | `true` | + +### Metric Service + +| Name | Description | Value | +|--------------------|----------------------------|--------| +| `metricdb.enabled` | Enable the Metric Service. | `true` | + ### Ingress | Name | Description | Value | -| ------------------------ | --------------------------------------------------------------------------------------------------------------- | -------------- | +|--------------------------|-----------------------------------------------------------------------------------------------------------------|----------------| | `ingress.enabled` | Enable the ingress. | `false` | | `ingress.className` | The ingress class name. | `nginx` | | `ingress.tls.enabled` | Enable the ingress. | `true` | diff --git a/helm/dbrepo/charts/dbrepo-mariadb-galera-1.4.6.tgz b/helm/dbrepo/charts/dbrepo-mariadb-galera-1.4.6.tgz new file mode 100644 index 0000000000000000000000000000000000000000..4af22ff6e998199f69a8e1ff43fd96c3f55aa8ec Binary files /dev/null and b/helm/dbrepo/charts/dbrepo-mariadb-galera-1.4.6.tgz differ diff --git a/helm/dbrepo/charts/grafana-10.1.1.tgz b/helm/dbrepo/charts/grafana-10.1.1.tgz new file mode 100644 index 0000000000000000000000000000000000000000..332c7758f160e873e5e5bebe46e5c0353aa03d88 Binary files /dev/null and b/helm/dbrepo/charts/grafana-10.1.1.tgz differ diff --git a/helm/dbrepo/charts/mariadb-14.1.4.tgz b/helm/dbrepo/charts/mariadb-14.1.4.tgz deleted file mode 100644 index 83f470bdcade4fdfc13b0d1f4f46095b877e3bcd..0000000000000000000000000000000000000000 Binary files a/helm/dbrepo/charts/mariadb-14.1.4.tgz and /dev/null differ diff --git a/helm/dbrepo/charts/prometheus-1.3.22.tgz b/helm/dbrepo/charts/prometheus-1.3.22.tgz new file mode 100644 index 0000000000000000000000000000000000000000..3d81a5e625af76257c1a7bc032e889005bc66607 Binary files /dev/null and b/helm/dbrepo/charts/prometheus-1.3.22.tgz differ diff --git a/helm/dbrepo/files/mariadb.json b/helm/dbrepo/files/mariadb.json new file mode 100644 index 0000000000000000000000000000000000000000..f53fe024185f6627f4b7fc592cca8135a9e03cd5 --- /dev/null +++ b/helm/dbrepo/files/mariadb.json @@ -0,0 +1,1377 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "description": "mariadb galera cluster overview. metrics from mysqld exporter.", + "editable": true, + "gnetId": 13106, + "graphTooltip": 0, + "id": null, + "iteration": 1601970485064, + "links": [], + "panels": [ + { + "datasource": { + "default": true, + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "fieldConfig": { + "defaults": { + "custom": { + "align": null, + "filterable": false + }, + "mappings": [ + { + "from": "", + "id": 0, + "text": "UP", + "to": "", + "type": 1, + "value": "1" + }, + { + "from": "", + "id": 1, + "text": "DOWN", + "to": "", + "type": 1, + "value": "0" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 0 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byType", + "options": "number" + }, + "properties": [ + { + "id": "custom.displayMode", + "value": "color-background" + }, + { + "id": "thresholds", + "value": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "green", + "value": 1 + } + ] + } + }, + { + "id": "custom.width", + "value": 200 + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 12, + "x": 0, + "y": 0 + }, + "id": 2, + "options": { + "showHeader": true, + "sortBy": [] + }, + "pluginVersion": "7.2.0", + "targets": [ + { + "expr": "mysql_up", + "format": "table", + "instant": true, + "interval": "", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Service Status", + "transformations": [ + { + "id": "filterFieldsByName", + "options": { + "include": { + "names": [ + "instance", + "Value" + ] + } + } + } + ], + "type": "table" + }, + { + "datasource": "P18F45E9DC7E75912", + "fieldConfig": { + "defaults": { + "custom": { + "align": null, + "filterable": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byType", + "options": "number" + }, + "properties": [ + { + "id": "unit", + "value": "s" + }, + { + "id": "custom.width", + "value": 200 + }, + { + "id": "custom.displayMode", + "value": "color-background" + }, + { + "id": "thresholds", + "value": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "green", + "value": 80 + } + ] + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 12, + "x": 12, + "y": 0 + }, + "id": 4, + "options": { + "showHeader": true + }, + "pluginVersion": "7.2.0", + "targets": [ + { + "expr": "mysql_global_status_uptime", + "format": "table", + "instant": true, + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Service Uptime", + "transformations": [ + { + "id": "filterFieldsByName", + "options": { + "include": { + "names": [ + "instance", + "Value" + ] + } + } + } + ], + "type": "table" + }, + { + "datasource": "P18F45E9DC7E75912", + "fieldConfig": { + "defaults": { + "custom": {}, + "mappings": [], + "max": 3, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "yellow", + "value": 1.0001 + }, + { + "color": "green", + "value": 2.0001 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 12, + "x": 0, + "y": 5 + }, + "id": 6, + "options": { + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true + }, + "pluginVersion": "7.2.0", + "targets": [ + { + "expr": "mysql_global_status_wsrep_cluster_size", + "format": "time_series", + "instant": false, + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Cluster Size", + "transformations": [ + { + "id": "labelsToFields", + "options": { + "valueLabel": "instance" + } + } + ], + "type": "gauge" + }, + { + "datasource": "P18F45E9DC7E75912", + "fieldConfig": { + "defaults": { + "custom": { + "align": null, + "filterable": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "green", + "value": 1 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 12, + "x": 12, + "y": 5 + }, + "id": 8, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "mean" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "7.2.0", + "targets": [ + { + "expr": "mysql_global_status_wsrep_cluster_status", + "instant": false, + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Cluster Status", + "transformations": [ + { + "id": "labelsToFields", + "options": { + "valueLabel": "instance" + } + } + ], + "transparent": true, + "type": "stat" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "P18F45E9DC7E75912", + "fieldConfig": { + "defaults": { + "custom": {}, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 10 + }, + "hiddenSeries": false, + "id": 16, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": 200, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.2.0", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(mysql_global_status_queries[1m])", + "interval": "", + "legendFormat": "{{ instance }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Current QPS", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "P18F45E9DC7E75912", + "fieldConfig": { + "defaults": { + "custom": {}, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 10 + }, + "hiddenSeries": false, + "id": 10, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": 200, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.2.0", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "mysql_global_status_max_used_connections", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "Current - {{ instance }}", + "refId": "A" + }, + { + "expr": "mysql_global_variables_max_connections", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "Max - {{ instance }}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Mysql Connections", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "P18F45E9DC7E75912", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 17 + }, + "hiddenSeries": false, + "id": 12, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": 200, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.2.0", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "write", + "transform": "negative-Y" + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "irate(mysql_global_status_innodb_data_reads[10m])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "reads - {{ instance }}", + "refId": "A" + }, + { + "expr": "irate(mysql_global_status_innodb_data_writes[10m])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "write - {{ instance }}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "mysql disk reads vs writes", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "P18F45E9DC7E75912", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 17 + }, + "hiddenSeries": false, + "id": 14, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": 200, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.2.0", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "/sent/", + "transform": "negative-Y" + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "irate(mysql_global_status_bytes_received[5m])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "received - {{ instance }}", + "refId": "A" + }, + { + "expr": "irate(mysql_global_status_bytes_sent[5m])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "sent - {{ instance }}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "mysql network received vs sent", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "P18F45E9DC7E75912", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 24 + }, + "hiddenSeries": false, + "id": 18, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.2.0", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "topk(5, rate(mysql_global_status_commands_total[5m]))", + "interval": "", + "legendFormat": "Com_{{ command }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Top Command Counters", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "P18F45E9DC7E75912", + "decimals": 2, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 32 + }, + "hiddenSeries": false, + "id": 20, + "legend": { + "alignAsTable": true, + "avg": true, + "current": false, + "max": true, + "min": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.2.0", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(mysql_global_status_opened_files[1m])", + "interval": "", + "legendFormat": "{{ instance }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "MySQL File Openings", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "P18F45E9DC7E75912", + "decimals": 2, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 32 + }, + "hiddenSeries": false, + "id": 22, + "legend": { + "alignAsTable": true, + "avg": true, + "current": false, + "max": true, + "min": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.2.0", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "mysql_global_status_open_files", + "interval": "", + "legendFormat": "Open Files - {{ instance }}", + "refId": "A" + }, + { + "expr": "mysql_global_variables_open_files_limit", + "interval": "", + "legendFormat": "Open Files Limit - {{ instance }}", + "refId": "B" + }, + { + "expr": "mysql_global_status_innodb_num_open_files", + "interval": "", + "legendFormat": "InnoDB Open Files - {{ instance }}", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "MySQL Open Files", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "P18F45E9DC7E75912", + "decimals": 1, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 40 + }, + "hiddenSeries": false, + "id": 24, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.2.0", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "irate(mysql_global_status_slow_queries[1m])", + "interval": "", + "legendFormat": "Slow Queries on {{ instance }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "MySQL Slow Queries", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:94", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "$$hashKey": "object:95", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "P18F45E9DC7E75912", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 40 + }, + "hiddenSeries": false, + "id": 26, + "legend": { + "alignAsTable": true, + "avg": true, + "current": false, + "max": true, + "min": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.2.0", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "irate(mysql_global_status_aborted_connects[1m])", + "interval": "", + "legendFormat": "Aborted Connects (attempts) on - {{ instance }}", + "refId": "A" + }, + { + "expr": "irate(mysql_global_status_aborted_clients[1m])", + "interval": "", + "legendFormat": "Aborted Clients (timeout) on - {{ instance }}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "MySQL Aborted Connections", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:206", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "$$hashKey": "object:207", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "1m", + "schemaVersion": 26, + "style": "dark", + "tags": ["provisioned", "galera", "mariadb"], + "templating": { + "list": [ + { + "datasource": "prometheus", + "filters": [], + "hide": 0, + "label": "", + "name": "Filters", + "skipUrlSync": false, + "type": "adhoc" + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "Galera/MariaDB - Overview", + "uid": "pXgz0qFGk", + "version": 2 +} \ No newline at end of file diff --git a/helm/dbrepo/files/rabbitmq.json b/helm/dbrepo/files/rabbitmq.json new file mode 100644 index 0000000000000000000000000000000000000000..a8db65695f2dfef0484ebd91fcb7401f31f9f70d --- /dev/null +++ b/helm/dbrepo/files/rabbitmq.json @@ -0,0 +1,8165 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "description": "A new RabbitMQ Management Overview", + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 1, + "id": null, + "iteration": 1659711638455, + "links": [ + { + "icon": "doc", + "tags": [], + "targetBlank": true, + "title": "Monitoring with Prometheus & Grafana", + "tooltip": "", + "type": "link", + "url": "https://www.rabbitmq.com/prometheus.html" + } + ], + "liveNow": false, + "panels": [ + { + "datasource": { + "default": true, + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#37872D", + "value": null + }, + { + "color": "#1F60C4", + "value": 10000 + }, + { + "color": "#C4162A", + "value": 100000 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "id": 64, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(rabbitmq_queue_messages_ready * on(instance, job) group_left(rabbitmq_cluster) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"})", + "format": "time_series", + "hide": false, + "instant": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "title": "Ready messages", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#C4162A", + "value": null + }, + { + "color": "#1F60C4", + "value": -1 + }, + { + "color": "#37872D", + "value": 50 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 6, + "y": 0 + }, + "id": 62, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(rate(rabbitmq_global_messages_received_total[60s]) * on(instance, job) group_left(rabbitmq_cluster) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"})", + "format": "time_series", + "instant": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "title": "Incoming messages / s", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#C4162A", + "value": null + }, + { + "color": "#1F60C4", + "value": 0 + }, + { + "color": "#37872D", + "value": 10 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 12, + "y": 0 + }, + "id": 66, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(rabbitmq_global_publishers * on(instance, job) group_left(rabbitmq_cluster) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"})", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "title": "Publishers", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#C4162A", + "value": null + }, + { + "color": "#1F60C4", + "value": 0 + }, + { + "color": "#37872D", + "value": 10 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 16, + "y": 0 + }, + "id": 37, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(rabbitmq_connections * on(instance, job) group_left(rabbitmq_cluster) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"})", + "format": "time_series", + "instant": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "title": "Connections", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#C4162A", + "value": null + }, + { + "color": "#1F60C4", + "value": 0 + }, + { + "color": "#37872D", + "value": 10 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 20, + "y": 0 + }, + "id": 40, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(rabbitmq_queues * on(instance, job) group_left(rabbitmq_cluster) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"})", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "title": "Queues", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#37872D", + "value": null + }, + { + "color": "#1F60C4", + "value": 100 + }, + { + "color": "#C4162A", + "value": 500 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 0, + "y": 3 + }, + "id": 65, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(rabbitmq_queue_messages_unacked * on(instance, job) group_left(rabbitmq_cluster) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"})", + "format": "time_series", + "hide": false, + "instant": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "title": "Unacknowledged messages", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#C4162A", + "value": null + }, + { + "color": "#1F60C4", + "value": -1 + }, + { + "color": "#37872D", + "value": 50 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 6, + "y": 3 + }, + "id": 63, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(rate(rabbitmq_global_messages_redelivered_total[60s]) * on(instance, job) group_left(rabbitmq_cluster) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}) +\nsum(rate(rabbitmq_global_messages_delivered_consume_auto_ack_total[60s]) * on(instance, job) group_left(rabbitmq_cluster) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}) +\nsum(rate(rabbitmq_global_messages_delivered_consume_manual_ack_total[60s]) * on(instance, job) group_left(rabbitmq_cluster) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}) +\nsum(rate(rabbitmq_global_messages_delivered_get_auto_ack_total[60s]) * on(instance, job) group_left(rabbitmq_cluster) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}) +\nsum(rate(rabbitmq_global_messages_delivered_get_manual_ack_total[60s]) * on(instance, job) group_left(rabbitmq_cluster) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"})", + "format": "time_series", + "hide": false, + "instant": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "title": "Outgoing messages / s", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#C4162A", + "value": null + }, + { + "color": "#1F60C4", + "value": 0 + }, + { + "color": "#37872D", + "value": 10 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 12, + "y": 3 + }, + "id": 41, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(rabbitmq_consumers * on(instance, job) group_left(rabbitmq_cluster) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"})", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "title": "Consumers", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#C4162A", + "value": null + }, + { + "color": "#1F60C4", + "value": 0 + }, + { + "color": "#37872D", + "value": 10 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 16, + "y": 3 + }, + "id": 38, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(rabbitmq_channels * on(instance, job) group_left(rabbitmq_cluster) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"})", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "title": "Channels", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#1F60C4", + "value": null + }, + { + "color": "#37872D", + "value": 3 + }, + { + "color": "#C4162A", + "value": 8 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 20, + "y": 3 + }, + "id": 67, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(rabbitmq_build_info * on(instance, job) group_left(rabbitmq_cluster) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"})", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "title": "Nodes", + "type": "stat" + }, + { + "collapsed": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 6 + }, + "id": 4, + "panels": [], + "title": "NODES", + "type": "row" + }, + { + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "displayMode": "auto" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "erlang_version" + }, + "properties": [ + { + "id": "displayName", + "value": "Erlang/OTP" + }, + { + "id": "unit", + "value": "none" + }, + { + "id": "custom.align" + }, + { + "id": "thresholds", + "value": { + "mode": "absolute", + "steps": [ + { + "color": "rgba(50, 172, 45, 0.97)", + "value": null + }, + { + "color": "rgba(237, 129, 40, 0.89)" + } + ] + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "rabbitmq_version" + }, + "properties": [ + { + "id": "displayName", + "value": "RabbitMQ" + }, + { + "id": "unit", + "value": "none" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + }, + { + "id": "thresholds", + "value": { + "mode": "absolute", + "steps": [ + { + "color": "rgba(245, 54, 54, 0.9)", + "value": null + }, + { + "color": "rgba(237, 129, 40, 0.89)" + } + ] + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "instance" + }, + "properties": [ + { + "id": "displayName", + "value": "Host" + }, + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "rabbitmq_node" + }, + "properties": [ + { + "id": "displayName", + "value": "Node name" + }, + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + }, + { + "id": "thresholds", + "value": { + "mode": "absolute", + "steps": [ + { + "color": "rgba(245, 54, 54, 0.9)", + "value": null + }, + { + "color": "rgba(237, 129, 40, 0.89)" + } + ] + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Time" + }, + "properties": [ + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Value" + }, + "properties": [ + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "job" + }, + "properties": [ + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "rabbitmq_cluster" + }, + "properties": [ + { + "id": "displayName", + "value": "Cluster" + }, + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "prometheus_client_version" + }, + "properties": [ + { + "id": "displayName", + "value": "prometheus.erl" + }, + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "prometheus_plugin_version" + }, + "properties": [ + { + "id": "displayName", + "value": "rabbitmq_prometheus" + }, + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 24, + "x": 0, + "y": 7 + }, + "id": 69, + "links": [], + "options": { + "footer": { + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "exemplar": false, + "expr": "rabbitmq_build_info * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}", + "format": "table", + "instant": true, + "interval": "", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "transformations": [ + { + "id": "merge", + "options": { + "reducers": [] + } + } + ], + "type": "table" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "If the value is zero or less, the memory alarm will be triggered and all publishing connections across all cluster nodes will be blocked.\n\nThis value can temporarily go negative because the memory alarm is triggered with a slight delay.\n\nThe kernel's view of the amount of memory used by the node can differ from what the node itself can observe. This means that this value can be negative for a sustained period of time.\n\nBy default nodes use resident set size (RSS) to compute how much memory they use. This strategy can be changed (see the guides below).\n\n* [Alarms](https://www.rabbitmq.com/alarms.html)\n* [Memory Alarms](https://www.rabbitmq.com/memory.html)\n* [Reasoning About Memory Use](https://www.rabbitmq.com/memory-use.html)\n* [Blocked Connection Notifications](https://www.rabbitmq.com/connection-blocked.html)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "line+area" + } + }, + "decimals": 1, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "orange", + "value": 0 + }, + { + "color": "transparent", + "value": 536870912 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?0(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#56A64B", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?1(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2CC0C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?2(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#3274D9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?3(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#A352CC", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?4(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FF780A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?5(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#96D98D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?6(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFEE52", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?7(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#8AB8FF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?8(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CA95E5", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?9(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFB357", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 11 + }, + "id": 7, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "(rabbitmq_resident_memory_limit_bytes * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}) -\n(rabbitmq_process_resident_memory_bytes * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"})", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "{{rabbitmq_node}}", + "refId": "A" + } + ], + "title": "Memory available before publishers blocked", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "This metric is reported for the partition where the RabbitMQ data directory is stored.\n\nIf the value is zero or less, the disk alarm will be triggered and all publishing connections across all cluster nodes will be blocked.\n\nThis value can temporarily go negative because the free disk space alarm is triggered with a slight delay.\n\n* [Alarms](https://www.rabbitmq.com/alarms.html)\n* [Disk Space Alarms](https://www.rabbitmq.com/disk-alarms.html)\n* [Disk Space](https://www.rabbitmq.com/production-checklist.html#resource-limits-disk-space)\n* [Persistence Configuration](https://www.rabbitmq.com/persistence-conf.html)\n* [Blocked Connection Notifications](https://www.rabbitmq.com/connection-blocked.html)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "line+area" + } + }, + "decimals": 1, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "orange", + "value": 1073741824 + }, + { + "color": "transparent", + "value": 5368709120 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?0(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#56A64B", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?1(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2CC0C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?2(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#3274D9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?3(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#A352CC", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?4(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FF780A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?5(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#96D98D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?6(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFEE52", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?7(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#8AB8FF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?8(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CA95E5", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?9(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFB357", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 12, + "y": 11 + }, + "id": 8, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "rabbitmq_disk_space_available_bytes * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "{{rabbitmq_node}}", + "refId": "A" + } + ], + "title": "Disk space available before publishers blocked", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "When this value reaches zero, new connections will not be accepted and disk write operations may fail.\n\nClient libraries, peer nodes and CLI tools will not be able to connect when the node runs out of available file descriptors.\n\n* [Open File Handles Limit](https://www.rabbitmq.com/production-checklist.html#resource-limits-file-handle-limit)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "line+area" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "orange", + "value": 500 + }, + { + "color": "transparent", + "value": 1000 + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?0(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#56A64B", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?1(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2CC0C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?2(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#3274D9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?3(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#A352CC", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?4(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FF780A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?5(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#96D98D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?6(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFEE52", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?7(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#8AB8FF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?8(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CA95E5", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?9(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFB357", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 20, + "y": 11 + }, + "id": 2, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "(rabbitmq_process_max_fds * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}) -\n(rabbitmq_process_open_fds * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"})", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "{{rabbitmq_node}}", + "refId": "A" + } + ], + "title": "File descriptors available", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "When this value reaches zero, new connections will not be accepted.\n\nClient libraries, peer nodes and CLI tools will not be able to connect when the node runs out of available file descriptors.\n\n* [Networking and RabbitMQ](https://www.rabbitmq.com/networking.html)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "line+area" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "orange", + "value": 500 + }, + { + "color": "transparent", + "value": 1000 + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?0(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#56A64B", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?1(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2CC0C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?2(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#3274D9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?3(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#A352CC", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?4(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FF780A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?5(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#96D98D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?6(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFEE52", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?7(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#8AB8FF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?8(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CA95E5", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?9(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFB357", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 20, + "y": 15 + }, + "id": 5, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "(rabbitmq_process_max_tcp_sockets * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}) -\n(rabbitmq_process_open_tcp_sockets * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"})", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "{{rabbitmq_node}}", + "refId": "A" + } + ], + "title": "TCP sockets available", + "type": "timeseries" + }, + { + "collapsed": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 19 + }, + "id": 27, + "panels": [], + "title": "QUEUED MESSAGES", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "Total number of ready messages ready to be delivered to consumers.\n\nAim to keep this value as low as possible. RabbitMQ behaves best when messages are flowing through it. It's OK for publishers to occasionally outpace consumers, but the expectation is that consumers will eventually process all ready messages.\n\nIf this metric keeps increasing, your system will eventually run out of memory and/or disk space. Consider using TTL or Queue Length Limit to prevent unbounded message growth.\n\n* [Queues](https://www.rabbitmq.com/queues.html)\n* [Consumers](https://www.rabbitmq.com/consumers.html)\n* [Queue Length Limit](https://www.rabbitmq.com/maxlength.html)\n* [Time-To-Live and Expiration](https://www.rabbitmq.com/ttl.html)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 0, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?0(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#56A64B", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?1(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2CC0C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?2(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#3274D9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?3(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#A352CC", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?4(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FF780A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?5(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#96D98D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?6(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFEE52", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?7(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#8AB8FF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?8(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CA95E5", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?9(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFB357", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 12, + "x": 0, + "y": 20 + }, + "id": 9, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(rabbitmq_queue_messages_ready * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}) by(rabbitmq_node)", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "{{rabbitmq_node}}", + "refId": "A" + } + ], + "title": "Messages ready to be delivered to consumers", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "The total number of messages that are either in-flight to consumers, currently being processed by consumers or simply waiting for the consumer acknowledgements to be processed by the queue. Until the queue processes the message acknowledgement, the message will remain unacknowledged.\n\n* [Queues](https://www.rabbitmq.com/queues.html)\n* [Confirms and Acknowledgements](https://www.rabbitmq.com/confirms.html)\n* [Consumer Prefetch](https://www.rabbitmq.com/consumer-prefetch.html)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 0, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?0(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#56A64B", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?1(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2CC0C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?2(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#3274D9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?3(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#A352CC", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?4(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FF780A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?5(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#96D98D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?6(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFEE52", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?7(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#8AB8FF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?8(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CA95E5", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?9(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFB357", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 12, + "x": 12, + "y": 20 + }, + "id": 19, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(rabbitmq_queue_messages_unacked * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}) by(rabbitmq_node)", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "{{rabbitmq_node}}", + "refId": "A" + } + ], + "title": "Messages pending consumer acknowledgement", + "type": "timeseries" + }, + { + "collapsed": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 25 + }, + "id": 11, + "panels": [], + "title": "INCOMING MESSAGES", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "The incoming message rate before any routing rules are applied.\n\nIf this value is lower than the number of messages published to queues, it may indicate that some messages are delivered to more than one queue.\n\nIf this value is higher than the number of messages published to queues, messages cannot be routed and will either be dropped or returned to publishers.\n\n* [Publishers](https://www.rabbitmq.com/publishers.html)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 0, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?0(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#56A64B", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?1(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2CC0C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?2(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#3274D9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?3(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#A352CC", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?4(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FF780A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?5(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#96D98D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?6(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFEE52", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?7(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#8AB8FF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?8(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CA95E5", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?9(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFB357", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 12, + "x": 0, + "y": 26 + }, + "id": 13, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(rate(rabbitmq_global_messages_received_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}) by(rabbitmq_node)", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "{{rabbitmq_node}}", + "refId": "A" + } + ], + "title": "Messages published / s", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "The rate of messages confirmed by the broker to publishers. Publishers must opt-in to receive message confirmations.\n\nIf this metric is consistently at zero it may suggest that publisher confirms are not used by clients. The safety of published messages is likely to be at risk.\n\n* [Publisher Confirms](https://www.rabbitmq.com/confirms.html#publisher-confirms)\n* [Publisher Confirms and Data Safety](https://www.rabbitmq.com/publishers.html#data-safety)\n* [When Will Published Messages Be Confirmed by the Broker?](https://www.rabbitmq.com/confirms.html#when-publishes-are-confirmed)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 0, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?0(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#56A64B", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?1(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2CC0C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?2(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#3274D9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?3(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#A352CC", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?4(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FF780A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?5(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#96D98D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?6(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFEE52", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?7(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#8AB8FF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?8(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CA95E5", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?9(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFB357", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 12, + "x": 12, + "y": 26 + }, + "id": 18, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(rate(rabbitmq_global_messages_confirmed_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}) by(rabbitmq_node)", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "{{rabbitmq_node}}", + "refId": "A" + } + ], + "title": "Messages confirmed to publishers / s", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "The rate of messages received from publishers and successfully routed to the master queue replicas.\n\n* [Queues](https://www.rabbitmq.com/queues.html)\n* [Publishers](https://www.rabbitmq.com/publishers.html)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 0, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?0(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#56A64B", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?1(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2CC0C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?2(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#3274D9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?3(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#A352CC", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?4(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FF780A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?5(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#96D98D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?6(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFEE52", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?7(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#8AB8FF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?8(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CA95E5", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?9(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFB357", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 12, + "x": 0, + "y": 31 + }, + "id": 61, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(rate(rabbitmq_global_messages_routed_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}) by(rabbitmq_node)", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "{{rabbitmq_node}}", + "refId": "A" + } + ], + "title": "Messages routed to queues / s", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "The rate of messages received from publishers that have publisher confirms enabled and the broker has not confirmed yet.\n\n* [Publishers](https://www.rabbitmq.com/publishers.html)\n* [Confirms and Acknowledgements](https://www.rabbitmq.com/confirms.html)\n* [When Will Published Messages Be Confirmed by the Broker?](https://www.rabbitmq.com/confirms.html#when-publishes-are-confirmed)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 0, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?0(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#56A64B", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?1(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2CC0C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?2(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#3274D9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?3(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#A352CC", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?4(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FF780A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?5(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#96D98D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?6(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFEE52", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?7(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#8AB8FF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?8(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CA95E5", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?9(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFB357", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 12, + "x": 12, + "y": 31 + }, + "id": 12, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(rate(rabbitmq_global_messages_received_confirm_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"} - \nrate(rabbitmq_global_messages_confirmed_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}\n) by(rabbitmq_node)", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "{{rabbitmq_node}}", + "refId": "A" + } + ], + "title": "Messages unconfirmed to publishers / s", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "The rate of messages that cannot be routed and are dropped. \n\nAny value above zero means message loss and likely suggests a routing problem on the publisher end.\n\n* [Unroutable Message Handling](https://www.rabbitmq.com/publishers.html#unroutable)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "line+area" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "transparent", + "value": null + }, + { + "color": "red", + "value": 0 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/rabbit/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C4162A", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 12, + "x": 0, + "y": 36 + }, + "id": 34, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(rate(rabbitmq_global_messages_unroutable_dropped_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}) by(rabbitmq_node)", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "{{rabbitmq_node}}", + "refId": "A" + } + ], + "title": "Unroutable messages dropped / s", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "The rate of messages that cannot be routed and are returned back to publishers.\n\nSustained values above zero may indicate a routing problem on the publisher end.\n\n* [Unroutable Message Handling](https://www.rabbitmq.com/publishers.html#unroutable)\n* [When Will Published Messages Be Confirmed by the Broker?](https://www.rabbitmq.com/confirms.html#when-publishes-are-confirmed)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "line+area" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "transparent", + "value": null + }, + { + "color": "red", + "value": 0 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/rabbit/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C4162A", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 12, + "x": 12, + "y": 36 + }, + "id": 16, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(rate(rabbitmq_global_messages_unroutable_returned_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}) by(rabbitmq_node)", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "{{rabbitmq_node}}", + "refId": "A" + } + ], + "title": "Unroutable messages returned to publishers / s", + "type": "timeseries" + }, + { + "collapsed": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 41 + }, + "id": 29, + "panels": [], + "title": "OUTGOING MESSAGES", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "The rate of messages delivered to consumers. It includes messages that have been redelivered.\n\nThis metric does not include messages that have been fetched by consumers using `basic.get` (consumed by polling).\n\n* [Consumers](https://www.rabbitmq.com/consumers.html)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 0, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?0(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#56A64B", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?1(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2CC0C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?2(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#3274D9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?3(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#A352CC", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?4(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FF780A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?5(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#96D98D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?6(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFEE52", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?7(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#8AB8FF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?8(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CA95E5", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?9(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFB357", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 12, + "x": 0, + "y": 42 + }, + "id": 14, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(\n (rate(rabbitmq_global_messages_delivered_consume_auto_ack_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}) +\n (rate(rabbitmq_global_messages_delivered_consume_manual_ack_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"})\n) by(rabbitmq_node)", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "{{rabbitmq_node}}", + "refId": "A" + } + ], + "title": "Messages delivered / s", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "The rate of messages that have been redelivered to consumers. It includes messages that have been requeued automatically and redelivered due to channel exceptions or connection closures.\n\nHaving some redeliveries is expected, but if this metric is consistently non-zero, it is worth investigating why.\n\n* [Negative Acknowledgement and Requeuing of Deliveries](https://www.rabbitmq.com/confirms.html#consumer-nacks-requeue)\n* [Consumers](https://www.rabbitmq.com/consumers.html)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "line+area" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "transparent", + "value": null + }, + { + "color": "orange", + "value": 20 + }, + { + "color": "red", + "value": 100 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?0(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#56A64B", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?1(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2CC0C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?2(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#3274D9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?3(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#A352CC", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?4(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FF780A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?5(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#96D98D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?6(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFEE52", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?7(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#8AB8FF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?8(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CA95E5", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?9(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFB357", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 12, + "x": 12, + "y": 42 + }, + "id": 15, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(rate(rabbitmq_global_messages_redelivered_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}) by(rabbitmq_node)", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "{{rabbitmq_node}}", + "refId": "A" + } + ], + "title": "Messages redelivered / s", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "The rate of message deliveries to consumers that use manual acknowledgement mode.\n\nWhen this mode is used, RabbitMQ waits for consumers to acknowledge messages before more messages can be delivered.\n\nThis is the safest way of consuming messages.\n\n* [Consumer Acknowledgements](https://www.rabbitmq.com/confirms.html)\n* [Consumer Prefetch](https://www.rabbitmq.com/consumer-prefetch.html)\n* [Consumer Acknowledgement Modes, Prefetch and Throughput](https://www.rabbitmq.com/confirms.html#channel-qos-prefetch-throughput)\n* [Consumers](https://www.rabbitmq.com/consumers.html)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 0, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?0(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#56A64B", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?1(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2CC0C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?2(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#3274D9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?3(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#A352CC", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?4(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FF780A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?5(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#96D98D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?6(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFEE52", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?7(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#8AB8FF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?8(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CA95E5", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?9(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFB357", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 12, + "x": 0, + "y": 47 + }, + "id": 20, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(rate(rabbitmq_global_messages_delivered_consume_manual_ack_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}) by(rabbitmq_node)", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "{{rabbitmq_node}}", + "refId": "A" + } + ], + "title": "Messages delivered with manual ack / s", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "The rate of message deliveries to consumers that use automatic acknowledgement mode.\n\nWhen this mode is used, RabbitMQ does not wait for consumers to acknowledge message deliveries.\n\nThis mode is fire-and-forget and does not offer any delivery safety guarantees. It tends to provide higher throughput and it may lead to consumer overload and higher consumer memory usage.\n\n* [Consumer Acknowledgement Modes, Prefetch and Throughput](https://www.rabbitmq.com/confirms.html#channel-qos-prefetch-throughput)\n* [Consumers](https://www.rabbitmq.com/consumers.html)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 0, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?0(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#56A64B", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?1(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2CC0C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?2(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#3274D9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?3(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#A352CC", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?4(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FF780A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?5(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#96D98D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?6(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFEE52", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?7(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#8AB8FF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?8(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CA95E5", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?9(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFB357", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 12, + "x": 12, + "y": 47 + }, + "id": 21, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(rate(rabbitmq_global_messages_delivered_consume_auto_ack_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}) by(rabbitmq_node)", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "{{rabbitmq_node}}", + "refId": "A" + } + ], + "title": "Messages delivered auto ack / s", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "The rate of message acknowledgements coming from consumers that use manual acknowledgement mode.\n\n* [Consumer Acknowledgements](https://www.rabbitmq.com/confirms.html)\n* [Consumer Prefetch](https://www.rabbitmq.com/consumer-prefetch.html)\n* [Consumer Acknowledgement Modes, Prefetch and Throughput](https://www.rabbitmq.com/confirms.html#channel-qos-prefetch-throughput)\n* [Consumers](https://www.rabbitmq.com/consumers.html)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 0, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?0(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#56A64B", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?1(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2CC0C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?2(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#3274D9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?3(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#A352CC", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?4(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FF780A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?5(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#96D98D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?6(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFEE52", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?7(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#8AB8FF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?8(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CA95E5", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?9(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFB357", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 12, + "x": 0, + "y": 52 + }, + "id": 22, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(rate(rabbitmq_global_messages_acknowledged_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}) by(rabbitmq_node)", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "{{rabbitmq_node}}", + "refId": "A" + } + ], + "title": "Messages acknowledged / s", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "The rate of messages delivered to polling consumers that use automatic acknowledgement mode.\n\nThe use of polling consumers is highly inefficient and therefore strongly discouraged.\n\n* [Fetching individual messages](https://www.rabbitmq.com/consumers.html#fetching)\n* [Consumers](https://www.rabbitmq.com/consumers.html)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "line+area" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "transparent", + "value": null + }, + { + "color": "red", + "value": 0 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/rabbit/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C4162A", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 12, + "x": 12, + "y": 52 + }, + "id": 24, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(rate(rabbitmq_global_messages_delivered_get_auto_ack_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}) by(rabbitmq_node)", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "{{rabbitmq_node}}", + "refId": "A" + } + ], + "title": "Polling operations with auto ack / s", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "The rate of polling consumer operations that yield no result.\n\nAny value above zero means that RabbitMQ resources are wasted by polling consumers.\n\nCompare this metric to the other polling consumer metrics to see the inefficiency rate.\n\nThe use of polling consumers is highly inefficient and therefore strongly discouraged.\n\n* [Fetching individual messages](https://www.rabbitmq.com/consumers.html#fetching)\n* [Consumers](https://www.rabbitmq.com/consumers.html)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "line+area" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "transparent", + "value": null + }, + { + "color": "red", + "value": 0 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/rabbit/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C4162A", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 12, + "x": 0, + "y": 57 + }, + "id": 25, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(rate(rabbitmq_global_messages_get_empty_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}) by(rabbitmq_node)", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "{{rabbitmq_node}}", + "refId": "A" + } + ], + "title": "Polling operations that yield no result / s", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "The rate of messages delivered to polling consumers that use manual acknowledgement mode.\n\nThe use of polling consumers is highly inefficient and therefore strongly discouraged.\n\n* [Fetching individual messages](https://www.rabbitmq.com/consumers.html#fetching)\n* [Consumers](https://www.rabbitmq.com/consumers.html)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "line+area" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "transparent", + "value": null + }, + { + "color": "red", + "value": 0 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/rabbit/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C4162A", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 12, + "x": 12, + "y": 57 + }, + "id": 23, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(rate(rabbitmq_global_messages_delivered_get_manual_ack_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}) by(rabbitmq_node)", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "{{rabbitmq_node}}", + "refId": "A" + } + ], + "title": "Polling operations with manual ack / s", + "type": "timeseries" + }, + { + "collapsed": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 62 + }, + "id": 53, + "panels": [], + "title": "QUEUES", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "Total number of queue masters per node. \n\nThis metric makes it easy to see sub-optimal queue distribution in a cluster.\n\n* [Queue Masters, Data Locality](https://www.rabbitmq.com/ha.html#master-migration-data-locality)\n* [Queues](https://www.rabbitmq.com/queues.html)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?0(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#56A64B", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?1(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2CC0C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?2(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#3274D9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?3(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#A352CC", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?4(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FF780A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?5(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#96D98D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?6(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFEE52", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?7(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#8AB8FF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?8(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CA95E5", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?9(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFB357", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 12, + "x": 0, + "y": 63 + }, + "id": 57, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "rabbitmq_queues * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}", + "format": "time_series", + "instant": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{rabbitmq_node}}", + "refId": "A" + } + ], + "title": "Total queues", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "The rate of queue declarations performed by clients.\n\nLow sustained values above zero are to be expected. High rates may be indicative of queue churn or high rates of connection recovery. Confirm connection recovery rates by using the _Connections opened_ metric.\n\n* [Queues](https://www.rabbitmq.com/queues.html)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "line+area" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "transparent", + "value": null + }, + { + "color": "orange", + "value": 2 + }, + { + "color": "red", + "value": 10 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?0(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#56A64B", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?1(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2CC0C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?2(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#3274D9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?3(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#A352CC", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?4(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FF780A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?5(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#96D98D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?6(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFEE52", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?7(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#8AB8FF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?8(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CA95E5", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?9(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFB357", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 4, + "x": 12, + "y": 63 + }, + "id": 58, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(rate(rabbitmq_queues_declared_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}) by(rabbitmq_node)", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "{{rabbitmq_node}}", + "refId": "A" + } + ], + "title": "Queues declared / s", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "The rate of new queues created (as opposed to redeclarations).\n\nLow sustained values above zero are to be expected. High rates may be indicative of queue churn or high rates of connection recovery. Confirm connection recovery rates by using the _Connections opened_ metric.\n\n* [Queues](https://www.rabbitmq.com/queues.html)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "line+area" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "transparent", + "value": null + }, + { + "color": "orange", + "value": 2 + }, + { + "color": "red", + "value": 10 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?0(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#56A64B", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?1(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2CC0C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?2(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#3274D9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?3(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#A352CC", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?4(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FF780A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?5(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#96D98D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?6(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFEE52", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?7(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#8AB8FF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?8(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CA95E5", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?9(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFB357", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 4, + "x": 16, + "y": 63 + }, + "id": 60, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(rate(rabbitmq_queues_created_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}) by(rabbitmq_node)", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "{{rabbitmq_node}}", + "refId": "A" + } + ], + "title": "Queues created / s", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "The rate of queues deleted.\n\nLow sustained values above zero are to be expected. High rates may be indicative of queue churn or high rates of connection recovery. Confirm connection recovery rates by using the _Connections opened_ metric.\n\n* [Queues](https://www.rabbitmq.com/queues.html)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "line+area" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "transparent", + "value": null + }, + { + "color": "orange", + "value": 2 + }, + { + "color": "red", + "value": 10 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?0(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#56A64B", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?1(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2CC0C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?2(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#3274D9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?3(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#A352CC", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?4(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FF780A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?5(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#96D98D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?6(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFEE52", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?7(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#8AB8FF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?8(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CA95E5", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?9(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFB357", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 4, + "x": 20, + "y": 63 + }, + "id": 59, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(rate(rabbitmq_queues_deleted_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}) by(rabbitmq_node)", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "{{rabbitmq_node}}", + "refId": "A" + } + ], + "title": "Queues deleted / s", + "type": "timeseries" + }, + { + "collapsed": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 68 + }, + "id": 51, + "panels": [], + "title": "CHANNELS", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "Total number of channels on all currently opened connections.\n\nIf this metric grows monotonically it is highly likely a channel leak in one of the applications. Confirm channel leaks by using the _Channels opened_ and _Channels closed_ metrics.\n\n* [Channel Leak](https://www.rabbitmq.com/channels.html#channel-leaks)\n* [Channels](https://www.rabbitmq.com/channels.html)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?0(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#56A64B", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?1(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2CC0C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?2(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#3274D9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?3(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#A352CC", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?4(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FF780A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?5(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#96D98D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?6(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFEE52", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?7(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#8AB8FF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?8(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CA95E5", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?9(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFB357", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 12, + "x": 0, + "y": 69 + }, + "id": 54, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "rabbitmq_channels * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "{{rabbitmq_node}}", + "refId": "A" + } + ], + "title": "Total channels", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "The rate of new channels opened by applications across all connections. Channels are expected to be long-lived.\n\nLow sustained values above zero are to be expected. High rates may be indicative of channel churn or mass connection recovery. Confirm connection recovery rates by using the _Connections opened_ metric.\n\n* [High Channel Churn](https://www.rabbitmq.com/channels.html#high-channel-churn)\n* [Channels](https://www.rabbitmq.com/channels.html)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "line+area" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "transparent", + "value": null + }, + { + "color": "orange", + "value": 2 + }, + { + "color": "red", + "value": 10 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?0(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#56A64B", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?1(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2CC0C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?2(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#3274D9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?3(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#A352CC", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?4(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FF780A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?5(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#96D98D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?6(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFEE52", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?7(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#8AB8FF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?8(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CA95E5", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?9(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFB357", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 6, + "x": 12, + "y": 69 + }, + "id": 55, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(rate(rabbitmq_channels_opened_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}) by(rabbitmq_node)", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "{{rabbitmq_node}}", + "refId": "A" + } + ], + "title": "Channels opened / s", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "The rate of channels closed by applications across all connections. Channels are expected to be long-lived.\n\nLow sustained values above zero are to be expected. High rates may be indicative of channel churn or mass connection recovery. Confirm connection recovery rates by using the _Connections opened_ metric.\n\n* [High Channel Churn](https://www.rabbitmq.com/channels.html#high-channel-churn)\n* [Channels](https://www.rabbitmq.com/channels.html)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "line+area" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "transparent", + "value": null + }, + { + "color": "orange", + "value": 2 + }, + { + "color": "red", + "value": 10 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?0(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#56A64B", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?1(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2CC0C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?2(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#3274D9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?3(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#A352CC", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?4(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FF780A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?5(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#96D98D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?6(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFEE52", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?7(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#8AB8FF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?8(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CA95E5", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?9(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFB357", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 6, + "x": 18, + "y": 69 + }, + "id": 56, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(rate(rabbitmq_channels_closed_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}) by(rabbitmq_node)", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "{{rabbitmq_node}}", + "refId": "A" + } + ], + "title": "Channels closed / s", + "type": "timeseries" + }, + { + "collapsed": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 74 + }, + "id": 46, + "panels": [], + "title": "CONNECTIONS", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "Total number of client connections.\n\nIf this metric grows monotonically it is highly likely a connection leak in one of the applications. Confirm connection leaks by using the _Connections opened_ and _Connections closed_ metrics.\n\n* [Connection Leak](https://www.rabbitmq.com/connections.html#monitoring)\n* [Connections](https://www.rabbitmq.com/connections.html)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?0(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#56A64B", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?1(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2CC0C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?2(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#3274D9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?3(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#A352CC", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?4(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FF780A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?5(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#96D98D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?6(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFEE52", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?7(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#8AB8FF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?8(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CA95E5", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?9(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFB357", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 12, + "x": 0, + "y": 75 + }, + "id": 47, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "rabbitmq_connections * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "{{rabbitmq_node}}", + "refId": "A" + } + ], + "title": "Total connections", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "The rate of new connections opened by clients. Connections are expected to be long-lived.\n\nLow sustained values above zero are to be expected. High rates may be indicative of connection churn or mass connection recovery.\n\n* [Connection Leak](https://www.rabbitmq.com/connections.html#monitoring)\n* [Connections](https://www.rabbitmq.com/connections.html)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "line+area" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "transparent", + "value": null + }, + { + "color": "orange", + "value": 2 + }, + { + "color": "red", + "value": 10 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?0(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#56A64B", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?1(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2CC0C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?2(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#3274D9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?3(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#A352CC", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?4(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FF780A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?5(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#96D98D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?6(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFEE52", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?7(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#8AB8FF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?8(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CA95E5", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?9(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFB357", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 6, + "x": 12, + "y": 75 + }, + "id": 48, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(rate(rabbitmq_connections_opened_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}) by(rabbitmq_node)", + "format": "time_series", + "instant": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{rabbitmq_node}}", + "refId": "A" + } + ], + "title": "Connections opened / s", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "The rate of connections closed. Connections are expected to be long-lived.\n\nLow sustained values above zero are to be expected. High rates may be indicative of connection churn or mass connection recovery.\n\n* [Connections](https://www.rabbitmq.com/connections.html)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "line+area" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "transparent", + "value": null + }, + { + "color": "orange", + "value": 2 + }, + { + "color": "red", + "value": 10 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?0(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#56A64B", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?1(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2CC0C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?2(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#3274D9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?3(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#A352CC", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?4(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FF780A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?5(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#96D98D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?6(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFEE52", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?7(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#8AB8FF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?8(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CA95E5", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^rabbit@[a-zA-Z\\.\\-]*?9(\\b|\\.)/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFB357", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 6, + "x": 18, + "y": 75 + }, + "id": 49, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "expr": "sum(rate(rabbitmq_connections_closed_total[60s]) * on(instance, job) group_left(rabbitmq_cluster, rabbitmq_node) rabbitmq_identity_info{rabbitmq_cluster=\"$rabbitmq_cluster\", namespace=\"$namespace\"}) by(rabbitmq_node)", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "{{rabbitmq_node}}", + "refId": "A" + } + ], + "title": "Connections closed / s", + "type": "timeseries" + } + ], + "refresh": "15s", + "schemaVersion": 34, + "style": "dark", + "tags": ["provisioned", "rabbitmq"], + "templating": { + "list": [ + { + "current": { + "selected": false, + "text": "default", + "value": "default" + }, + "datasource": "PBFA97CFB590B2093", + "hide": 2, + "includeAll": false, + "label": "datasource", + "multi": false, + "name": "DS_PROMETHEUS", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "definition": "label_values(rabbitmq_identity_info, namespace)", + "hide": 0, + "includeAll": false, + "label": "Namespace", + "multi": false, + "name": "namespace", + "options": [], + "query": { + "query": "label_values(rabbitmq_identity_info, namespace)", + "refId": "Prometheus-namespace-Variable-Query" + }, + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "definition": "label_values(rabbitmq_identity_info{namespace=\"$namespace\"}, rabbitmq_cluster)", + "hide": 0, + "includeAll": false, + "label": "RabbitMQ Cluster", + "multi": false, + "name": "rabbitmq_cluster", + "options": [], + "query": { + "query": "label_values(rabbitmq_identity_info{namespace=\"$namespace\"}, rabbitmq_cluster)", + "refId": "Prometheus-rabbitmq_cluster-Variable-Query" + }, + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-15m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "15s", + "30s", + "1m", + "5m", + "10m" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "RabbitMQ - Overview", + "uid": "Kn5xm-gZk", + "version": 20220805, + "weekStart": "", + "gnetId": 10991 +} \ No newline at end of file diff --git a/helm/dbrepo/files/system.json b/helm/dbrepo/files/system.json new file mode 100644 index 0000000000000000000000000000000000000000..52bf6d067122e2e803d2858256bfb274351d1f49 --- /dev/null +++ b/helm/dbrepo/files/system.json @@ -0,0 +1,1821 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 1, + "links": [ + { + "asDropdown": false, + "icon": "external link", + "includeVars": false, + "keepTime": false, + "tags": [], + "targetBlank": false, + "title": "Docs", + "tooltip": "", + "type": "link", + "url": "https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.4.6/" + } + ], + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 15, + "panels": [], + "title": "Data", + "type": "row" + }, + { + "datasource": { + "default": true, + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 0, + "y": 1 + }, + "id": 4, + "options": { + "colorMode": "background", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "10.4.9", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "dbrepo_database_count", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Databases", + "type": "stat" + }, + { + "datasource": { + "default": true, + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 4, + "y": 1 + }, + "id": 5, + "options": { + "colorMode": "background", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "10.4.9", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "dbrepo_view_count", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "Views", + "useBackend": false + }, + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "dbrepo_subset_count", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "Subsets", + "useBackend": false + }, + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "dbrepo_table_count", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "Tables", + "useBackend": false + } + ], + "title": "Datasources", + "transformations": [ + { + "id": "calculateField", + "options": { + "alias": "", + "mode": "reduceRow", + "reduce": { + "reducer": "sum" + }, + "replaceFields": true + } + } + ], + "type": "stat" + }, + { + "datasource": { + "default": true, + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "description": "", + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "decbytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 8, + "y": 1 + }, + "id": 8, + "options": { + "colorMode": "background", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "10.4.9", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "dbrepo_volume_sum", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Data Volume", + "type": "stat" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 4 + }, + "id": 22, + "panels": [], + "title": "UI", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "description": "", + "fieldConfig": { + "defaults": { + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "#EAB839", + "value": 300 + }, + { + "color": "orange", + "value": 600 + }, + { + "color": "red", + "value": 900 + } + ] + }, + "unit": "ms" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 0, + "y": 5 + }, + "id": 17, + "options": { + "colorMode": "background", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "10.4.9", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "disableTextWrap": false, + "editorMode": "code", + "expr": "avg(page_render_time)", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "UI Response Time (avg)", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "description": "", + "fieldConfig": { + "defaults": { + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "#EAB839", + "value": 0.02 + }, + { + "color": "orange", + "value": 0.05 + }, + { + "color": "red", + "value": 0.1 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 4, + "y": 5 + }, + "id": 24, + "options": { + "colorMode": "background", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "10.4.9", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "disableTextWrap": false, + "editorMode": "code", + "expr": "nodejs_eventloop_lag_mean_seconds", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "UI Event Lag (avg)", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "description": "", + "fieldConfig": { + "defaults": { + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 8, + "y": 5 + }, + "id": 25, + "options": { + "colorMode": "background", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "10.4.9", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "disableTextWrap": false, + "editorMode": "code", + "expr": "nodejs_active_handles{type=\"Server\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "UI Servers", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "description": "", + "fieldConfig": { + "defaults": { + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 12, + "y": 5 + }, + "id": 26, + "options": { + "colorMode": "background", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "10.4.9", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "disableTextWrap": false, + "editorMode": "code", + "expr": "nodejs_active_handles{type=\"Socket\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "UI Sockets", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "blue", + "mode": "fixed" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 16, + "y": 5 + }, + "id": 27, + "options": { + "colorMode": "background", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "10.4.9", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "disableTextWrap": false, + "editorMode": "code", + "expr": "nodejs_active_requests_total", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Active Requests", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 300 + }, + { + "color": "orange", + "value": 600 + }, + { + "color": "red", + "value": 900 + } + ] + }, + "unit": "ms" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 8 + }, + "id": 20, + "options": { + "displayMode": "basic", + "maxVizHeight": 300, + "minVizHeight": 16, + "minVizWidth": 8, + "namePlacement": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showUnfilled": true, + "sizing": "auto", + "valueMode": "color" + }, + "pluginVersion": "10.4.9", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "page_render_time", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{{path}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "UI Response Time per Path (avg)", + "type": "bargauge" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "smooth", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "dashed" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 256000000 + } + ] + }, + "unit": "decbytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 8 + }, + "id": 21, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "nodejs_heap_space_size_total_bytes", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{{space}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "NodeJS Heap Bytes", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 15 + }, + "id": 2, + "panels": [], + "title": "Services", + "type": "row" + }, + { + "datasource": { + "default": true, + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "description": "Quality of Service", + "fieldConfig": { + "defaults": { + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "purple", + "value": null + }, + { + "color": "red", + "value": 0 + }, + { + "color": "orange", + "value": 60 + }, + { + "color": "#EAB839", + "value": 80 + }, + { + "color": "green", + "value": 100 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 0, + "y": 16 + }, + "id": 9, + "options": { + "colorMode": "background", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "10.4.9", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "disableTextWrap": false, + "editorMode": "code", + "expr": "sum(up)*100/count(up)", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "Services Running", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "QoS", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "description": "", + "fieldConfig": { + "defaults": { + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 4, + "y": 16 + }, + "id": 28, + "options": { + "colorMode": "background", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "10.4.9", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "disableTextWrap": false, + "editorMode": "code", + "expr": "min(process_uptime_seconds)", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Uptime", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "fillOpacity": 70, + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "mappings": [ + { + "options": { + "0": { + "index": 0, + "text": "DOWN" + }, + "1": { + "index": 1, + "text": "UP" + } + }, + "type": "value" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "green", + "value": 1 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 16 + }, + "id": 16, + "options": { + "colWidth": 0.9, + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "rowHeight": 0.9, + "showValue": "auto", + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "up", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{{instance}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Service QoS", + "type": "status-history" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "smooth", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 19 + }, + "id": 23, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "10.4.9", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "disableTextWrap": false, + "editorMode": "code", + "expr": "process_open_fds\n", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{{instance}}", + "range": true, + "refId": "process_open_fds", + "useBackend": false + } + ], + "title": "File Descriptors", + "type": "timeseries" + }, + { + "datasource": { + "default": true, + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "description": "Heap and non-heap memory summed", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 25, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "smooth", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "decbytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "auth-service:9000" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "data-service:8080" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "metadata-service:8080" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "metadata-service:80" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 23 + }, + "id": 7, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "11.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "sum by(instance) (jvm_memory_used_bytes)", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": false, + "instant": false, + "legendFormat": "{{instance}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "JVM Memory Usage", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 25, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "smooth", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "auth-service:9000" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "data-service:8080" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "metadata-service:8080" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "metadata-service:80" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 26 + }, + "id": 6, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "11.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "process_cpu_usage", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{{instance}}", + "range": true, + "refId": "process_cpu_usage", + "useBackend": false + } + ], + "title": "CPU Usage", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 25, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "smooth", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "reqps" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*search-service.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*analyse-service.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "super-light-orange", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 30 + }, + "id": 19, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "editorMode": "code", + "expr": "rate(flask_http_request_duration_seconds_count{status!~\"200|201|202\"}[$__rate_interval])", + "instant": false, + "legendFormat": "{{method}} {{instance}} ({{status}})", + "range": true, + "refId": "A" + } + ], + "title": "Failed API Requests", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 25, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "smooth", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "reqps" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*search-service.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*analyse-service.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "super-light-orange", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 33 + }, + "id": 18, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "editorMode": "code", + "expr": "rate(flask_http_request_duration_seconds_count{status=~\"200|201|202\",path!=\"/health\"}[$__rate_interval])", + "instant": false, + "legendFormat": "{{method}} {{instance}} {{path}} ({{status}})", + "range": true, + "refId": "A" + } + ], + "title": "Successful API Requests", + "type": "timeseries" + } + ], + "refresh": "1m", + "schemaVersion": 39, + "tags": [ + "provisioned", + "dbrepo" + ], + "templating": { + "list": [] + }, + "time": { + "from": "now-30m", + "to": "now" + }, + "timepicker": {}, + "timezone": "browser", + "title": "DBRepo - Overview", + "uid": "bdz20owu8zn5se", + "version": 1, + "weekStart": "" +} \ No newline at end of file diff --git a/helm/dbrepo/templates/_names.tpl b/helm/dbrepo/templates/_names.tpl new file mode 100644 index 0000000000000000000000000000000000000000..cea9dae390ea083c43da813edeefa5441c007f0e --- /dev/null +++ b/helm/dbrepo/templates/_names.tpl @@ -0,0 +1,6 @@ +{{/* +Allow the release namespace to be overridden for multi-namespace deployments in combined charts. +*/}} +{{- define "common.names.namespace" -}} +{{- default .Release.Namespace .Values.namespaceOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} \ No newline at end of file diff --git a/helm/dbrepo/templates/analyse-deployment.yaml b/helm/dbrepo/templates/analyse-deployment.yaml index 68d43e9cee8cab5e4f2073c3e23965e87f9197fe..3adf32f77840cfe588d58d8a7202adc4681e6d7d 100644 --- a/helm/dbrepo/templates/analyse-deployment.yaml +++ b/helm/dbrepo/templates/analyse-deployment.yaml @@ -4,7 +4,7 @@ apiVersion: apps/v1 kind: Deployment metadata: name: analyse-service - namespace: {{ .Values.namespace }} + namespace: {{ include "common.names.namespace" . | quote }} labels: app: analyse-service service: analyse-service @@ -45,15 +45,15 @@ spec: - -ec - "curl -sSL localhost:8080/health | grep 'UP' || exit 1" initialDelaySeconds: 120 - periodSeconds: 30 + periodSeconds: 10 readinessProbe: exec: command: - /bin/bash - -ec - "curl -sSL localhost:8080/health | grep 'UP' || exit 1" - initialDelaySeconds: 10 - periodSeconds: 30 + initialDelaySeconds: 30 + periodSeconds: 10 {{- if .Values.analyseservice.resources }} resources: {{- toYaml .Values.analyseservice.resources | nindent 12 }} {{- end }} diff --git a/helm/dbrepo/templates/analyse-secret.yaml b/helm/dbrepo/templates/analyse-secret.yaml index 2b8b78dbd5a14ed01f5f21d0e3aabaa25b518c36..49aa8938296b07342350f9749d9b62d078acbdb9 100644 --- a/helm/dbrepo/templates/analyse-secret.yaml +++ b/helm/dbrepo/templates/analyse-secret.yaml @@ -4,7 +4,7 @@ apiVersion: v1 kind: Secret metadata: name: analyse-service-secret - namespace: {{ .Values.namespace }} + namespace: {{ include "common.names.namespace" . | quote }} stringData: ADMIN_USERNAME: "{{ .Values.identityservice.users }}" ADMIN_PASSWORD: "{{ .Values.identityservice.userPasswords }}" diff --git a/helm/dbrepo/templates/analyse-service.yaml b/helm/dbrepo/templates/analyse-service.yaml index 98720e3e4656c8fd80f1fff35b27a02846371cd1..0f9ac322d99310e0766df792f1b28c06f2477c4f 100644 --- a/helm/dbrepo/templates/analyse-service.yaml +++ b/helm/dbrepo/templates/analyse-service.yaml @@ -4,7 +4,7 @@ apiVersion: v1 kind: Service metadata: name: analyse-service - namespace: {{ $.Values.namespace }} + namespace: {{ include "common.names.namespace" . | quote }} labels: service: analyse-service spec: diff --git a/helm/dbrepo/templates/auth-configmap.yaml b/helm/dbrepo/templates/auth-configmap.yaml index 269d18c99d7800101afc8ac1c3528104fad7243c..557d99072513ec0330848d467db2501982853c0e 100644 --- a/helm/dbrepo/templates/auth-configmap.yaml +++ b/helm/dbrepo/templates/auth-configmap.yaml @@ -3,7 +3,7 @@ apiVersion: v1 kind: ConfigMap metadata: name: auth-service-config - namespace: {{ $.Values.namespace }} + namespace: {{ include "common.names.namespace" . | quote }} data: KC_HOSTNAME_PATH: "/api/auth" KC_HOSTNAME_ADMIN_URL: "{{ .Values.gateway }}/api/auth" @@ -540,7 +540,7 @@ data: "description" : "${default-container-handling}", "composite" : true, "composites" : { - "realm" : [ "find-container", "list-containers" ] + "realm" : [ "find-container" ] }, "clientRole" : false, "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", @@ -2153,7 +2153,7 @@ data: "subType" : "anonymous", "subComponents" : { }, "config" : { - "allowed-protocol-mapper-types" : [ "oidc-full-name-mapper", "saml-user-attribute-mapper", "saml-user-property-mapper", "saml-role-list-mapper", "oidc-usermodel-attribute-mapper", "oidc-usermodel-property-mapper", "oidc-address-mapper", "oidc-sha256-pairwise-sub-mapper" ] + "allowed-protocol-mapper-types" : [ "saml-user-attribute-mapper", "oidc-full-name-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-address-mapper", "saml-user-property-mapper", "oidc-usermodel-property-mapper", "oidc-usermodel-attribute-mapper", "saml-role-list-mapper" ] } }, { "id" : "1849e52a-b8c9-44a8-af3d-ee19376a1ed1", @@ -2179,7 +2179,7 @@ data: "subType" : "authenticated", "subComponents" : { }, "config" : { - "allowed-protocol-mapper-types" : [ "saml-user-property-mapper", "oidc-usermodel-property-mapper", "saml-role-list-mapper", "oidc-address-mapper", "saml-user-attribute-mapper", "oidc-full-name-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-usermodel-attribute-mapper" ] + "allowed-protocol-mapper-types" : [ "saml-role-list-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-full-name-mapper", "oidc-usermodel-property-mapper", "oidc-usermodel-attribute-mapper", "saml-user-property-mapper", "saml-user-attribute-mapper", "oidc-address-mapper" ] } } ], "org.keycloak.storage.UserStorageProvider" : [ { @@ -2195,8 +2195,8 @@ data: "config" : { "ldap.attribute" : [ "createTimestamp" ], "is.mandatory.in.ldap" : [ "false" ], - "always.read.value.from.ldap" : [ "true" ], "read.only" : [ "true" ], + "always.read.value.from.ldap" : [ "true" ], "user.model.attribute" : [ "createTimestamp" ] } }, { @@ -2219,8 +2219,8 @@ data: "config" : { "ldap.attribute" : [ "cn" ], "is.mandatory.in.ldap" : [ "true" ], - "read.only" : [ "false" ], "always.read.value.from.ldap" : [ "true" ], + "read.only" : [ "false" ], "user.model.attribute" : [ "firstName" ] } }, { @@ -2231,8 +2231,8 @@ data: "config" : { "ldap.attribute" : [ "mail" ], "is.mandatory.in.ldap" : [ "false" ], - "read.only" : [ "false" ], "always.read.value.from.ldap" : [ "false" ], + "read.only" : [ "false" ], "user.model.attribute" : [ "email" ] } }, { @@ -2245,13 +2245,13 @@ data: "group.name.ldap.attribute" : [ "cn" ], "preserve.group.inheritance" : [ "false" ], "membership.user.ldap.attribute" : [ "uid" ], - "groups.dn" : [ "ou=users,{{ .Values.identityservice.global.ldapDomain }}" ], + "groups.dn" : [ "ou=users,dc=dbrepo,dc=at" ], "mode" : [ "LDAP_ONLY" ], "user.roles.retrieve.strategy" : [ "LOAD_GROUPS_BY_MEMBER_ATTRIBUTE" ], - "membership.ldap.attribute" : [ "member" ], "ignore.missing.groups" : [ "false" ], - "group.object.classes" : [ "groupOfNames" ], + "membership.ldap.attribute" : [ "member" ], "memberof.ldap.attribute" : [ "memberOf" ], + "group.object.classes" : [ "groupOfNames" ], "groups.path" : [ "/" ], "drop.non.existing.groups.during.sync" : [ "false" ] } @@ -2263,8 +2263,8 @@ data: "config" : { "ldap.attribute" : [ "modifyTimestamp" ], "is.mandatory.in.ldap" : [ "false" ], - "always.read.value.from.ldap" : [ "true" ], "read.only" : [ "true" ], + "always.read.value.from.ldap" : [ "true" ], "user.model.attribute" : [ "modifyTimestamp" ] } }, { @@ -2277,25 +2277,25 @@ data: "is.mandatory.in.ldap" : [ "true" ], "attribute.force.default" : [ "false" ], "is.binary.attribute" : [ "false" ], - "always.read.value.from.ldap" : [ "false" ], "read.only" : [ "false" ], + "always.read.value.from.ldap" : [ "false" ], "user.model.attribute" : [ "username" ] } } ] }, "config" : { - "pagination" : [ "false" ], "fullSyncPeriod" : [ "-1" ], + "pagination" : [ "false" ], "startTls" : [ "false" ], - "usersDn" : [ "ou=users,dc=dbrepo,dc=at" ], + "usersDn" : [ "ou=users,{{ .Values.identityservice.global.ldapDomain }}" ], "connectionPooling" : [ "true" ], "cachePolicy" : [ "DEFAULT" ], "useKerberosForPasswordAuthentication" : [ "false" ], "importEnabled" : [ "true" ], "enabled" : [ "true" ], - "usernameLDAPAttribute" : [ "uid" ], - "bindCredential" : [ "{{ .Values.identityservice.global.adminPassword }}" ], "bindDn" : [ "cn={{ .Values.identityservice.global.adminUser }},{{ .Values.identityservice.global.ldapDomain }}" ], + "bindCredential" : [ "{{ .Values.identityservice.global.adminPassword }}" ], + "usernameLDAPAttribute" : [ "uid" ], "changedSyncPeriod" : [ "-1" ], "lastSync" : [ "1719252666" ], "vendor" : [ "other" ], diff --git a/helm/dbrepo/templates/broker-secret.yaml b/helm/dbrepo/templates/broker-secret.yaml index 4348be52896a8cb09672379ed10cf746803651e8..7a207d4bcd6db8486408361cf816aa169b8357cb 100644 --- a/helm/dbrepo/templates/broker-secret.yaml +++ b/helm/dbrepo/templates/broker-secret.yaml @@ -4,7 +4,7 @@ apiVersion: v1 kind: Secret metadata: name: broker-service-secret - namespace: {{ .Values.namespace }} + namespace: {{ include "common.names.namespace" . | quote }} stringData: advanced.config: | [ diff --git a/helm/dbrepo/templates/dashboard-configmap.yaml b/helm/dbrepo/templates/dashboard-configmap.yaml new file mode 100644 index 0000000000000000000000000000000000000000..9643f539d2ae7b4aec491f1ba7b73b9202daa85f --- /dev/null +++ b/helm/dbrepo/templates/dashboard-configmap.yaml @@ -0,0 +1,11 @@ +{{- if .Values.dashboardservice.enabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: dashboard-service-config + namespace: {{ include "common.names.namespace" . | quote }} +data: + {{ (.Files.Glob "files/system.json").AsConfig | nindent 2 }} + {{ (.Files.Glob "files/rabbitmq.json").AsConfig | nindent 2 }} + {{ (.Files.Glob "files/mariadb.json").AsConfig | nindent 2 }} +{{- end }} \ No newline at end of file diff --git a/helm/dbrepo/templates/dashboard-secret.yaml b/helm/dbrepo/templates/dashboard-secret.yaml new file mode 100644 index 0000000000000000000000000000000000000000..c224c1d17b2352b228b7ed3f8946eaec0366b595 --- /dev/null +++ b/helm/dbrepo/templates/dashboard-secret.yaml @@ -0,0 +1,58 @@ +{{- if .Values.dashboardservice.enabled }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: dashboard-service-secret + namespace: {{ include "common.names.namespace" . | quote }} +stringData: + GF_SERVER_PROTOCOL: "http" + GF_SERVER_DOMAIN: "dashboard-service" + GF_SERVER_ROOT_URL: "http://%(domain)s/dashboard/" + GF_AUTH_ANONYMOUS_ENABLED: "true" + GF_AUTH_ANONYMOUS_ORG_ROLE: "Viewer" + GF_SERVER_SERVE_FROM_SUB_PATH: "true" + GF_SECURITY_DISABLE_INITIAL_ADMIN_CREATION: "true" + LDAP_ADMIN_USERNAME: "{{ .Values.identityservice.global.adminUser }}" + LDAP_ADMIN_PASSWORD: "{{ .Values.identityservice.global.adminPassword }}" + LDAP_ROOT: "{{ .Values.identityservice.global.ldapDomain }}" + ldap.toml: | + [[servers]] + host = "identity-service" + port = 389 + use_ssl = false + + # Search user bind dn + bind_dn = "cn=${LDAP_ADMIN_USERNAME},${LDAP_ROOT}" + bind_password = "${LDAP_ADMIN_PASSWORD}" + + # Timeout in seconds. Applies to each host specified in the 'host' entry (space separated). + timeout = 10 + + # User search filter, for example "(cn=%s)" or "(sAMAccountName=%s)" or "(uid=%s)" + # Allow login from email or username, example "(|(sAMAccountName=%s)(userPrincipalName=%s))" + search_filter = "(cn=%s)" + + # An array of base dns to search through + search_base_dns = ["${LDAP_ROOT}"] + + group_search_base_dns = ["ou=users,${LDAP_ROOT}"] + group_search_filter = "(&(objectClass=groupOfNames)(member=cn=%s,ou=users,${LDAP_ROOT}))" + group_search_filter_user_attribute = "uid" + + [servers.attributes] + name = "givenName" + surname = "sn" + username = "cn" + member_of = "member" + email = "email" + + [[servers.group_mappings]] + group_dn = "cn=${LDAP_ADMIN_USERNAME},ou=users,${LDAP_ROOT}" + org_role = "Admin" + grafana_admin = true + + [[servers.group_mappings]] + group_dn = "*" + org_role = "Viewer" +{{- end }} diff --git a/helm/dbrepo/templates/data-db-secret.yaml b/helm/dbrepo/templates/data-db-secret.yaml index 100c1ce82c5ce7aa3da112a83a1af4b8825105ef..e12d638ac98abdba410c4091ece9bc237bd07e92 100644 --- a/helm/dbrepo/templates/data-db-secret.yaml +++ b/helm/dbrepo/templates/data-db-secret.yaml @@ -4,7 +4,7 @@ apiVersion: v1 kind: Secret metadata: name: data-db-secret - namespace: {{ .Values.namespace }} + namespace: {{ include "common.names.namespace" . | quote }} stringData: S3_ACCESS_KEY_ID: "{{ .Values.storageservice.s3.auth.adminAccessKeyId }}" S3_SECRET_ACCESS_KEY: "{{ .Values.storageservice.s3.auth.adminSecretAccessKey }}" diff --git a/helm/dbrepo/templates/data-deployment.yaml b/helm/dbrepo/templates/data-deployment.yaml index 1d9e2352bd080702d61f94cf32915cba841293ad..fae3250738ef0952f974a2ec1fa4498c03f9d231 100644 --- a/helm/dbrepo/templates/data-deployment.yaml +++ b/helm/dbrepo/templates/data-deployment.yaml @@ -4,7 +4,7 @@ apiVersion: apps/v1 kind: Deployment metadata: name: data-service - namespace: {{ .Values.namespace }} + namespace: {{ include "common.names.namespace" . | quote }} labels: app: data-service service: data-service @@ -45,7 +45,7 @@ spec: - -ec - "curl -sSL localhost:8080/actuator/health/readiness | grep 'UP' || exit 1" initialDelaySeconds: 120 - periodSeconds: 30 + periodSeconds: 10 readinessProbe: exec: command: @@ -53,7 +53,7 @@ spec: - -ec - "curl -sSL localhost:8080/actuator/health/liveness | grep 'UP' || exit 1" initialDelaySeconds: 30 - periodSeconds: 30 + periodSeconds: 10 {{- if .Values.dataservice.resources }} resources: {{- toYaml .Values.dataservice.resources | nindent 12 }} {{- end }} diff --git a/helm/dbrepo/templates/data-secret.yaml b/helm/dbrepo/templates/data-secret.yaml index 52740b930db06675e6069ef400ea1d44a3dbddc1..dd40e3e649ab6b679510871184e4ee7e09d11c31 100644 --- a/helm/dbrepo/templates/data-secret.yaml +++ b/helm/dbrepo/templates/data-secret.yaml @@ -3,7 +3,7 @@ apiVersion: v1 kind: Secret metadata: name: data-service-secret - namespace: {{ .Values.namespace }} + namespace: {{ include "common.names.namespace" . | quote }} stringData: ADMIN_EMAIL: "{{ .Values.metadataservice.admin.email }}" AUTH_SERVICE_ADMIN: "{{ .Values.authservice.auth.adminUser }}" diff --git a/helm/dbrepo/templates/data-service.yaml b/helm/dbrepo/templates/data-service.yaml index 279ce21f48fcc6727ac307e0abf6619cdcd9efcb..17fed741d6193f80f930f2118dbb5d59e396278f 100644 --- a/helm/dbrepo/templates/data-service.yaml +++ b/helm/dbrepo/templates/data-service.yaml @@ -4,7 +4,7 @@ apiVersion: v1 kind: Service metadata: name: data-service - namespace: {{ .Values.namespace }} + namespace: {{ include "common.names.namespace" . | quote }} labels: service: data-service spec: diff --git a/helm/dbrepo/templates/ingress.yaml b/helm/dbrepo/templates/ingress.yaml index b2cc8d0d507094d26a00664b36c0c79684c9e54f..364416c1a43c192d2993e6f17b39ec43cd8d9095 100644 --- a/helm/dbrepo/templates/ingress.yaml +++ b/helm/dbrepo/templates/ingress.yaml @@ -4,7 +4,7 @@ kind: Ingress metadata: name: dbrepo-ingress-basic annotations: {{ toYaml .Values.ingress.annotations.basic | nindent 4 }} - namespace: {{ .Values.namespace }} + namespace: {{ include "common.names.namespace" . | quote }} spec: ingressClassName: {{ .Values.ingress.className }} {{- if .Values.ingress.tls.enabled }} @@ -157,6 +157,13 @@ spec: name: upload-service port: number: 80 + - path: /dashboard + pathType: Prefix + backend: + service: + name: dashboard-service + port: + number: 3000 - path: / pathType: Prefix backend: @@ -170,7 +177,7 @@ kind: Ingress metadata: name: dbrepo-ingress-admin annotations: {{ toYaml .Values.ingress.annotations.rewriteApi | nindent 4 }} - namespace: {{ .Values.namespace }} + namespace: {{ include "common.names.namespace" . | quote }} spec: ingressClassName: {{ .Values.ingress.className }} {{- if .Values.ingress.tls.enabled }} @@ -196,7 +203,7 @@ kind: Ingress metadata: name: dbrepo-ingress-rewrite-root annotations: {{ toYaml .Values.ingress.annotations.rewriteRoot | nindent 4 }} - namespace: {{ .Values.namespace }} + namespace: {{ include "common.names.namespace" . | quote }} spec: ingressClassName: {{ .Values.ingress.className }} {{- if .Values.ingress.tls.enabled }} @@ -222,7 +229,7 @@ kind: Ingress metadata: name: dbrepo-ingress-rewrite-root-secure annotations: {{ toYaml .Values.ingress.annotations.rewriteRootSecure | nindent 4 }} - namespace: {{ .Values.namespace }} + namespace: {{ include "common.names.namespace" . | quote }} spec: ingressClassName: {{ .Values.ingress.className }} {{- if .Values.ingress.tls.enabled }} @@ -248,7 +255,7 @@ kind: Ingress metadata: name: dbrepo-ingress-pid annotations: {{ toYaml .Values.ingress.annotations.rewritePid | nindent 4 }} - namespace: {{ .Values.namespace }} + namespace: {{ include "common.names.namespace" . | quote }} spec: ingressClassName: {{ .Values.ingress.className }} {{- if .Values.ingress.tls.enabled }} diff --git a/helm/dbrepo/templates/metadata-configmap.yaml b/helm/dbrepo/templates/metadata-configmap.yaml index 9fd137bb39201b6149f5cce21c5c37c0f7ad6b20..893f255627c17b9ddf0a3ad765527857b3f9982b 100644 --- a/helm/dbrepo/templates/metadata-configmap.yaml +++ b/helm/dbrepo/templates/metadata-configmap.yaml @@ -4,7 +4,7 @@ apiVersion: v1 kind: ConfigMap metadata: name: metadata-db-setup - namespace: {{ .Values.namespace }} + namespace: {{ include "common.names.namespace" . | quote }} data: {{- with .Values.metadatadb.extraInitDbScripts }} {{ toYaml . | nindent 2 }} @@ -12,7 +12,7 @@ data: 02-setup-data.sql: | BEGIN; INSERT INTO `mdb_containers` (name, internal_name, image_id, host, port, sidecar_host, sidecar_port, privileged_username, privileged_password) - VALUES ('MariaDB 11.1.3', 'mariadb_11_1_3', 1, 'data-db', 3306, 'data-db', 8080, 'root', 'dbrepo'); + VALUES ('mariadb:11.1.3-debian-11-r6', 'mariadb_11_1_3', 1, 'data-db', 3306, 'data-db', 8080, 'root', 'dbrepo'); COMMIT; 01-setup-schema.sql: | BEGIN; @@ -36,7 +36,7 @@ data: CREATE TABLE IF NOT EXISTS `mdb_images` ( - id bigint NOT NULL AUTO_INCREMENT, + id SERIAL, registry character varying(255) NOT NULL DEFAULT 'docker.io', name character varying(255) NOT NULL, version character varying(255) NOT NULL, @@ -44,29 +44,17 @@ data: dialect character varying(255) NOT NULL, driver_class character varying(255) NOT NULL, jdbc_method character varying(255) NOT NULL, + is_default BOOLEAN NOT NULL DEFAULT FALSE, created timestamp NOT NULL DEFAULT NOW(), last_modified timestamp, PRIMARY KEY (id), - UNIQUE (name, version) - ) WITH SYSTEM VERSIONING; - - CREATE TABLE IF NOT EXISTS `mdb_images_date` - ( - id bigint NOT NULL AUTO_INCREMENT, - iid bigint NOT NULL, - database_format character varying(255) NOT NULL, - unix_format character varying(255) NOT NULL, - example character varying(255) NOT NULL, - has_time boolean NOT NULL, - created_at timestamp NOT NULL DEFAULT NOW(), - PRIMARY KEY (id), - FOREIGN KEY (iid) REFERENCES mdb_images (id), - UNIQUE (database_format, unix_format, example) + UNIQUE (name, version), + UNIQUE (is_default) ) WITH SYSTEM VERSIONING; CREATE TABLE IF NOT EXISTS `mdb_containers` ( - id bigint NOT NULL AUTO_INCREMENT, + id SERIAL, internal_name character varying(255) NOT NULL, name character varying(255) NOT NULL, host character varying(255) NOT NULL, @@ -81,13 +69,13 @@ data: last_modified timestamp, privileged_username character varying(255) NOT NULL, privileged_password character varying(255) NOT NULL, - PRIMARY KEY (id), - FOREIGN KEY (image_id) REFERENCES mdb_images (id) + quota integer NOT NULL DEFAULT 50, + PRIMARY KEY (id) ) WITH SYSTEM VERSIONING; CREATE TABLE IF NOT EXISTS `mdb_data` ( - ID bigint NOT NULL AUTO_INCREMENT, + ID SERIAL, PROVENANCE text, FileEncoding text, FileType character varying(100), @@ -107,8 +95,8 @@ data: CREATE TABLE IF NOT EXISTS `mdb_databases` ( - id bigint NOT NULL AUTO_INCREMENT, - cid bigint NOT NULL, + id SERIAL, + cid BIGINT UNSIGNED NOT NULL, name character varying(255) NOT NULL, internal_name character varying(255) NOT NULL, exchange_name character varying(255) NOT NULL, @@ -122,7 +110,7 @@ data: created timestamp NOT NULL DEFAULT NOW(), last_modified timestamp, PRIMARY KEY (id), - FOREIGN KEY (cid) REFERENCES mdb_containers (id) /* currently we only support one-to-one */, + FOREIGN KEY (cid) REFERENCES mdb_containers (id), FOREIGN KEY (created_by) REFERENCES mdb_users (id), FOREIGN KEY (owned_by) REFERENCES mdb_users (id), FOREIGN KEY (contact_person) REFERENCES mdb_users (id) @@ -137,8 +125,8 @@ data: CREATE TABLE IF NOT EXISTS `mdb_tables` ( - ID bigint NOT NULL AUTO_INCREMENT, - tDBID bigint NOT NULL, + ID SERIAL, + tDBID BIGINT UNSIGNED NOT NULL, tName VARCHAR(64) NOT NULL, internal_name VARCHAR(64) NOT NULL, queue_name VARCHAR(255) NOT NULL, @@ -169,35 +157,35 @@ data: CREATE TABLE IF NOT EXISTS `mdb_columns` ( - ID BIGINT NOT NULL AUTO_INCREMENT, - tID BIGINT NOT NULL, - dfID BIGINT, + ID SERIAL, + tID BIGINT UNSIGNED NOT NULL, cName VARCHAR(64), - internal_name VARCHAR(64) NOT NULL, + internal_name VARCHAR(64) NOT NULL, Datatype ENUM ('CHAR','VARCHAR','BINARY','VARBINARY','TINYBLOB','TINYTEXT','TEXT','BLOB','MEDIUMTEXT','MEDIUMBLOB','LONGTEXT','LONGBLOB','ENUM','SET','BIT','TINYINT','BOOL','SMALLINT','MEDIUMINT','INT','BIGINT','FLOAT','DOUBLE','DECIMAL','DATE','DATETIME','TIMESTAMP','TIME','YEAR'), - length BIGINT NULL, - ordinal_position INTEGER NOT NULL, - index_length BIGINT NULL, + length BIGINT UNSIGNED NULL, + ordinal_position INTEGER NOT NULL, + index_length BIGINT UNSIGNED NULL, description VARCHAR(2048), - size BIGINT, - d BIGINT, - auto_generated BOOLEAN DEFAULT false, - is_null_allowed BOOLEAN NOT NULL DEFAULT true, - val_min NUMERIC NULL, - val_max NUMERIC NULL, - mean NUMERIC NULL, - median NUMERIC NULL, - std_dev Numeric NULL, - created timestamp NOT NULL DEFAULT NOW(), + size BIGINT UNSIGNED, + d BIGINT UNSIGNED, + auto_generated BOOLEAN DEFAULT false, + is_null_allowed BOOLEAN NOT NULL DEFAULT true, + val_min NUMERIC NULL, + val_max NUMERIC NULL, + mean NUMERIC NULL, + median NUMERIC NULL, + std_dev Numeric NULL, + created timestamp NOT NULL DEFAULT NOW(), last_modified timestamp, FOREIGN KEY (tID) REFERENCES mdb_tables (ID) ON DELETE CASCADE, - PRIMARY KEY (ID) + PRIMARY KEY (ID), + UNIQUE (tID, internal_name) ) WITH SYSTEM VERSIONING; CREATE TABLE IF NOT EXISTS `mdb_columns_enums` ( - id bigint NOT NULL AUTO_INCREMENT, - column_id bigint NOT NULL, + id SERIAL, + column_id BIGINT UNSIGNED NOT NULL, value CHARACTER VARYING(255) NOT NULL, FOREIGN KEY (column_id) REFERENCES mdb_columns (ID) ON DELETE CASCADE, PRIMARY KEY (id) @@ -205,8 +193,8 @@ data: CREATE TABLE IF NOT EXISTS `mdb_columns_sets` ( - id bigint NOT NULL AUTO_INCREMENT, - column_id bigint NOT NULL, + id SERIAL, + column_id BIGINT UNSIGNED NOT NULL, value CHARACTER VARYING(255) NOT NULL, FOREIGN KEY (column_id) REFERENCES mdb_columns (ID) ON DELETE CASCADE, PRIMARY KEY (id) @@ -214,36 +202,36 @@ data: CREATE TABLE IF NOT EXISTS `mdb_columns_nom` ( - tID bigint, - cID bigint, + cID BIGINT UNSIGNED, + tID BIGINT UNSIGNED, maxlength INTEGER, last_modified timestamp, created timestamp NOT NULL DEFAULT NOW(), - FOREIGN KEY (tID, cID) REFERENCES mdb_columns (tID, ID), - PRIMARY KEY (tID, cID) + PRIMARY KEY (cID), + FOREIGN KEY (cID) REFERENCES mdb_columns (ID) ) WITH SYSTEM VERSIONING; CREATE TABLE IF NOT EXISTS `mdb_columns_cat` ( - tID bigint, - cID bigint, + cID BIGINT UNSIGNED, + tID BIGINT UNSIGNED, num_cat INTEGER, -- cat_array TEXT[], last_modified timestamp, created timestamp NOT NULL DEFAULT NOW(), - FOREIGN KEY (tID, cID) REFERENCES mdb_columns (tID, ID), - PRIMARY KEY (tID, cID) + PRIMARY KEY (cID), + FOREIGN KEY (cID) REFERENCES mdb_columns (ID) ) WITH SYSTEM VERSIONING; CREATE TABLE IF NOT EXISTS `mdb_constraints_foreign_key` ( - fkid BIGINT NOT NULL AUTO_INCREMENT, - tid BIGINT NOT NULL, - rtid BIGINT NOT NULL, - name VARCHAR(255) NOT NULL, - on_update VARCHAR(50) NULL, - on_delete VARCHAR(50) NULL, - position INT NULL, + fkid BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, + tid BIGINT UNSIGNED NOT NULL, + rtid BIGINT UNSIGNED NOT NULL, + name VARCHAR(255) NOT NULL, + on_update VARCHAR(50) NULL, + on_delete VARCHAR(50) NULL, + position INT NULL, PRIMARY KEY (fkid), FOREIGN KEY (tid) REFERENCES mdb_tables (id) ON DELETE CASCADE, FOREIGN KEY (rtid) REFERENCES mdb_tables (id) @@ -251,9 +239,9 @@ data: CREATE TABLE IF NOT EXISTS `mdb_constraints_primary_key` ( - pkid BIGINT NOT NULL AUTO_INCREMENT, - tID BIGINT NOT NULL, - cid BIGINT NOT NULL, + pkid SERIAL, + tID BIGINT UNSIGNED NOT NULL, + cid BIGINT UNSIGNED NOT NULL, PRIMARY KEY (pkid), FOREIGN KEY (tID) REFERENCES mdb_tables (id) ON DELETE CASCADE, FOREIGN KEY (cid) REFERENCES mdb_columns (id) ON DELETE CASCADE @@ -261,11 +249,12 @@ data: CREATE TABLE IF NOT EXISTS `mdb_constraints_foreign_key_reference` ( - id BIGINT NOT NULL AUTO_INCREMENT, - fkid BIGINT NOT NULL, - cid BIGINT NOT NULL, - rcid BIGINT NOT NULL, + id SERIAL, + fkid BIGINT UNSIGNED NOT NULL, + cid BIGINT UNSIGNED NOT NULL, + rcid BIGINT UNSIGNED NOT NULL, PRIMARY KEY (id), + UNIQUE (fkid, cid, rcid), FOREIGN KEY (fkid) REFERENCES mdb_constraints_foreign_key (fkid) ON UPDATE CASCADE, FOREIGN KEY (cid) REFERENCES mdb_columns (id), FOREIGN KEY (rcid) REFERENCES mdb_columns (id) @@ -273,19 +262,19 @@ data: CREATE TABLE IF NOT EXISTS `mdb_constraints_unique` ( - uid BIGINT NOT NULL AUTO_INCREMENT, - name VARCHAR(255) NOT NULL, - tid BIGINT NOT NULL, - position INT NULL, + uid BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, + name VARCHAR(255) NOT NULL, + tid BIGINT UNSIGNED NOT NULL, + position INT NULL, PRIMARY KEY (uid), FOREIGN KEY (tid) REFERENCES mdb_tables (id) ON DELETE CASCADE ); CREATE TABLE IF NOT EXISTS `mdb_constraints_unique_columns` ( - id BIGINT NOT NULL AUTO_INCREMENT, - uid BIGINT NOT NULL, - cid BIGINT NOT NULL, + id SERIAL, + uid BIGINT UNSIGNED NOT NULL, + cid BIGINT UNSIGNED NOT NULL, PRIMARY KEY (id), FOREIGN KEY (uid) REFERENCES mdb_constraints_unique (uid), FOREIGN KEY (cid) REFERENCES mdb_columns (id) ON DELETE CASCADE @@ -293,9 +282,9 @@ data: CREATE TABLE IF NOT EXISTS `mdb_constraints_checks` ( - id BIGINT NOT NULL AUTO_INCREMENT, - tid BIGINT NOT NULL, - checks VARCHAR(255) NOT NULL, + id SERIAL, + tid BIGINT UNSIGNED NOT NULL, + checks VARCHAR(255) NOT NULL, PRIMARY KEY (id), FOREIGN KEY (tid) REFERENCES mdb_tables (id) ON DELETE CASCADE ) WITH SYSTEM VERSIONING; @@ -303,7 +292,7 @@ data: CREATE TABLE IF NOT EXISTS `mdb_concepts` ( - id bigint NOT NULL AUTO_INCREMENT, + id SERIAL, uri text not null, name VARCHAR(255) null, description TEXT null, @@ -314,7 +303,7 @@ data: CREATE TABLE IF NOT EXISTS `mdb_units` ( - id bigint NOT NULL AUTO_INCREMENT, + id SERIAL, uri text not null, name VARCHAR(255) null, description TEXT null, @@ -325,26 +314,26 @@ data: CREATE TABLE IF NOT EXISTS `mdb_columns_concepts` ( - id bigint NOT NULL, - cID bigint NOT NULL, - created timestamp NOT NULL DEFAULT NOW(), + id BIGINT UNSIGNED NOT NULL, + cID BIGINT UNSIGNED NOT NULL, + created timestamp NOT NULL DEFAULT NOW(), PRIMARY KEY (id, cid), FOREIGN KEY (cID) REFERENCES mdb_columns (ID) ) WITH SYSTEM VERSIONING; CREATE TABLE IF NOT EXISTS `mdb_columns_units` ( - id bigint NOT NULL, - cID bigint NOT NULL, - created timestamp NOT NULL DEFAULT NOW(), + id BIGINT UNSIGNED NOT NULL, + cID BIGINT UNSIGNED NOT NULL, + created timestamp NOT NULL DEFAULT NOW(), PRIMARY KEY (id, cID), FOREIGN KEY (cID) REFERENCES mdb_columns (ID) ) WITH SYSTEM VERSIONING; CREATE TABLE IF NOT EXISTS `mdb_view` ( - id bigint NOT NULL AUTO_INCREMENT, - vdbid bigint NOT NULL, + id SERIAL, + vdbid BIGINT UNSIGNED NOT NULL, vName VARCHAR(64) NOT NULL, internal_name VARCHAR(64) NOT NULL, Query TEXT NOT NULL, @@ -361,7 +350,7 @@ data: CREATE TABLE IF NOT EXISTS `mdb_banner_messages` ( - id bigint NOT NULL AUTO_INCREMENT, + id SERIAL, type ENUM ('ERROR', 'WARNING', 'INFO') NOT NULL default 'INFO', message TEXT NOT NULL, link TEXT NULL, @@ -373,7 +362,7 @@ data: CREATE TABLE IF NOT EXISTS `mdb_ontologies` ( - id bigint NOT NULL AUTO_INCREMENT, + id SERIAL, prefix VARCHAR(8) NOT NULL, uri TEXT NOT NULL, uri_pattern TEXT, @@ -388,28 +377,28 @@ data: CREATE TABLE IF NOT EXISTS `mdb_view_columns` ( - id BIGINT NOT NULL AUTO_INCREMENT, - view_id BIGINT NOT NULL, - dfID BIGINT, + id SERIAL, + view_id BIGINT UNSIGNED NOT NULL, + dfID BIGINT UNSIGNED, name VARCHAR(64), - internal_name VARCHAR(64) NOT NULL, + internal_name VARCHAR(64) NOT NULL, column_type ENUM ('CHAR','VARCHAR','BINARY','VARBINARY','TINYBLOB','TINYTEXT','TEXT','BLOB','MEDIUMTEXT','MEDIUMBLOB','LONGTEXT','LONGBLOB','ENUM','SET','BIT','TINYINT','BOOL','SMALLINT','MEDIUMINT','INT','BIGINT','FLOAT','DOUBLE','DECIMAL','DATE','DATETIME','TIMESTAMP','TIME','YEAR'), - ordinal_position INTEGER NOT NULL, - size BIGINT, - d BIGINT, - auto_generated BOOLEAN DEFAULT false, - is_null_allowed BOOLEAN NOT NULL DEFAULT true, + ordinal_position INTEGER NOT NULL, + size BIGINT UNSIGNED, + d BIGINT UNSIGNED, + auto_generated BOOLEAN DEFAULT false, + is_null_allowed BOOLEAN NOT NULL DEFAULT true, PRIMARY KEY (id), - FOREIGN KEY (view_id) REFERENCES mdb_view (id) + FOREIGN KEY (view_id) REFERENCES mdb_view (id) ON DELETE CASCADE ) WITH SYSTEM VERSIONING; CREATE TABLE IF NOT EXISTS `mdb_identifiers` ( - id BIGINT NOT NULL AUTO_INCREMENT, - dbid BIGINT NOT NULL, - qid BIGINT, - vid BIGINT, - tid BIGINT, + id SERIAL, + dbid BIGINT UNSIGNED NOT NULL, + qid BIGINT UNSIGNED, + vid BIGINT UNSIGNED, + tid BIGINT UNSIGNED, publisher VARCHAR(255) NOT NULL, language VARCHAR(2), publication_year INTEGER NOT NULL, @@ -434,8 +423,8 @@ data: CREATE TABLE IF NOT EXISTS `mdb_identifier_licenses` ( - pid bigint NOT NULL, - license_id VARCHAR(255) NOT NULL, + pid BIGINT UNSIGNED NOT NULL, + license_id VARCHAR(255) NOT NULL, PRIMARY KEY (pid, license_id), FOREIGN KEY (pid) REFERENCES mdb_identifiers (id), FOREIGN KEY (license_id) REFERENCES mdb_licenses (identifier) @@ -443,9 +432,9 @@ data: CREATE TABLE IF NOT EXISTS `mdb_identifier_titles` ( - id bigint NOT NULL AUTO_INCREMENT, - pid bigint NOT NULL, - title text NOT NULL, + id SERIAL, + pid BIGINT UNSIGNED NOT NULL, + title text NOT NULL, title_type ENUM ('ALTERNATIVE_TITLE', 'SUBTITLE', 'TRANSLATED_TITLE', 'OTHER'), language VARCHAR(2), PRIMARY KEY (id), @@ -454,9 +443,9 @@ data: CREATE TABLE IF NOT EXISTS `mdb_identifier_funders` ( - id bigint NOT NULL AUTO_INCREMENT, - pid bigint NOT NULL, - funder_name VARCHAR(255) NOT NULL, + id SERIAL, + pid BIGINT UNSIGNED NOT NULL, + funder_name VARCHAR(255) NOT NULL, funder_identifier TEXT, funder_identifier_type ENUM ('CROSSREF_FUNDER_ID', 'GRID', 'ISNI', 'ROR', 'OTHER'), scheme_uri text, @@ -469,9 +458,9 @@ data: CREATE TABLE IF NOT EXISTS `mdb_identifier_descriptions` ( - id bigint NOT NULL AUTO_INCREMENT, - pid bigint NOT NULL, - description text NOT NULL, + id SERIAL, + pid BIGINT UNSIGNED NOT NULL, + description text NOT NULL, description_type ENUM ('ABSTRACT', 'METHODS', 'SERIES_INFORMATION', 'TABLE_OF_CONTENTS', 'TECHNICAL_INFO', 'OTHER'), language VARCHAR(2), PRIMARY KEY (id), @@ -480,11 +469,11 @@ data: CREATE TABLE IF NOT EXISTS `mdb_related_identifiers` ( - id bigint NOT NULL AUTO_INCREMENT, - pid bigint NOT NULL, - value varchar(255) NOT NULL, - type varchar(255) NOT NULL, - relation varchar(255) NOT NULL, + id SERIAL, + pid BIGINT UNSIGNED NOT NULL, + value varchar(255) NOT NULL, + type varchar(255) NOT NULL, + relation varchar(255) NOT NULL, PRIMARY KEY (id), /* must be a single id from persistent identifier concept */ FOREIGN KEY (pid) REFERENCES mdb_identifiers (id), UNIQUE (pid, value) @@ -492,11 +481,11 @@ data: CREATE TABLE IF NOT EXISTS `mdb_identifier_creators` ( - id bigint NOT NULL AUTO_INCREMENT, - pid bigint NOT NULL, + id SERIAL, + pid BIGINT UNSIGNED NOT NULL, given_names text, family_name text, - creator_name VARCHAR(255) NOT NULL, + creator_name VARCHAR(255) NOT NULL, name_type ENUM ('PERSONAL', 'ORGANIZATIONAL') default 'PERSONAL', name_identifier text, name_identifier_scheme ENUM ('ROR', 'GRID', 'ISNI', 'ORCID'), @@ -512,7 +501,7 @@ data: CREATE TABLE IF NOT EXISTS `mdb_update` ( uUserID character varying(255) NOT NULL, - uDBID bigint NOT NULL, + uDBID BIGINT UNSIGNED NOT NULL, created timestamp NOT NULL DEFAULT NOW(), PRIMARY KEY (uUserID, uDBID), FOREIGN KEY (uDBID) REFERENCES mdb_databases (id) @@ -521,7 +510,7 @@ data: CREATE TABLE IF NOT EXISTS `mdb_access` ( aUserID character varying(255) NOT NULL, - aDBID bigint REFERENCES mdb_databases (id), + aDBID BIGINT UNSIGNED REFERENCES mdb_databases (id), attime TIMESTAMP, download BOOLEAN, created timestamp NOT NULL DEFAULT NOW(), @@ -531,14 +520,40 @@ data: CREATE TABLE IF NOT EXISTS `mdb_have_access` ( user_id character varying(36) NOT NULL, - database_id bigint REFERENCES mdb_databases (id), + database_id BIGINT UNSIGNED REFERENCES mdb_databases (id), access_type ENUM ('READ', 'WRITE_OWN', 'WRITE_ALL') NOT NULL, created timestamp NOT NULL DEFAULT NOW(), PRIMARY KEY (user_id, database_id), FOREIGN KEY (user_id) REFERENCES mdb_users (id) ) WITH SYSTEM VERSIONING; + CREATE TABLE IF NOT EXISTS `mdb_image_types` + ( + id SERIAL, + image_id BIGINT UNSIGNED NOT NULL, + display_name varchar(255) NOT NULL, + value varchar(255) NOT NULL, + size_min INT UNSIGNED, + size_max INT UNSIGNED, + size_default INT UNSIGNED, + size_required BOOLEAN COMMENT 'When setting NULL, the service assumes the data type has no size', + size_step INT UNSIGNED, + d_min INT UNSIGNED, + d_max INT UNSIGNED, + d_default INT UNSIGNED, + d_required BOOLEAN COMMENT 'When setting NULL, the service assumes the data type has no d', + d_step INT UNSIGNED, + hint TEXT, + documentation TEXT NOT NULL, + is_quoted BOOLEAN NOT NULL, + is_buildable BOOLEAN NOT NULL, + PRIMARY KEY (id), + FOREIGN KEY (image_id) REFERENCES `mdb_images` (`id`), + UNIQUE (value) + ) WITH SYSTEM VERSIONING; + COMMIT; + BEGIN; INSERT INTO `mdb_licenses` (identifier, uri, description) @@ -551,13 +566,71 @@ data: VALUES ('mariadb', 'docker.io', '11.1.3', 3306, 'org.hibernate.dialect.MariaDBDialect', 'org.mariadb.jdbc.Driver', 'mariadb'); - INSERT INTO `mdb_images_date` (iid, database_format, unix_format, example, has_time) - VALUES (1, '%Y-%c-%d %H:%i:%S.%f', 'yyyy-MM-dd HH:mm:ss.SSSSSS', '2022-01-30 13:44:25.499', true), - (1, '%Y-%c-%d %H:%i:%S', 'yyyy-MM-dd HH:mm:ss', '2022-01-30 13:44:25', true), - (1, '%Y-%c-%d', 'yyyy-MM-dd', '2022-01-30', false), - (1, '%H:%i:%S', 'HH:mm:ss', '13:44:25', true); - - INSERT INTO `mdb_ontologies` (prefix, uri, uri_pattern, sparql_endpoint, rdf_path) + INSERT INTO `mdb_image_types` (image_id, display_name, value, size_min, size_max, size_default, size_required, + size_step, d_min, d_max, d_default, d_required, d_step, hint, documentation, is_quoted, + is_buildable) + VALUES (1, 'BIGINT(size)', 'bigint', 0, null, null, false, 1, null, null, null, null, null, null, + 'https://mariadb.com/kb/en/bigint/', false, true), + (1, 'BINARY(size)', 'binary', 0, 255, 255, true, 1, null, null, null, null, null, 'size in Bytes', + 'https://mariadb.com/kb/en/binary/', false, true), + (1, 'BIT(size)', 'bit', 0, 64, null, false, 1, null, null, null, null, null, null, + 'https://mariadb.com/kb/en/bit/', false, true), + (1, 'BLOB(size)', 'blob', 0, 65535, null, false, 1, null, null, null, null, null, 'size in Bytes', + 'https://mariadb.com/kb/en/blob/', false, false), + (1, 'BOOL', 'bool', null, null, null, null, null, null, null, null, null, null, null, + 'https://mariadb.com/kb/en/bool/', false, true), + (1, 'CHAR(size)', 'char', 0, 255, 255, false, 1, null, null, null, null, null, null, + 'https://mariadb.com/kb/en/char/', false, true), + (1, 'DATE', 'date', null, null, null, null, null, null, null, null, null, null, + 'min. 1000-01-01, max. 9999-12-31', 'https://mariadb.com/kb/en/date/', true, true), + (1, 'DATETIME(fsp)', 'datetime', 0, 6, null, null, 1, null, null, null, null, null, + 'fsp=microsecond precision, min. 1000-01-01 00:00:00.0, max. 9999-12-31 23:59:59.9', + 'https://mariadb.com/kb/en/datetime/', true, true), + (1, 'DECIMAL(size, d)', 'decimal', 0, 65, null, false, 1, 0, 38, null, false, null, null, + 'https://mariadb.com/kb/en/decimal/', false, true), + (1, 'DOUBLE(size, d)', 'double', null, null, null, false, null, null, null, null, false, null, null, + 'https://mariadb.com/kb/en/double/', false, true), + (1, 'ENUM(v1,v2,...)', 'enum', null, null, null, null, null, null, null, null, null, null, null, + 'https://mariadb.com/kb/en/enum/', true, true), + (1, 'FLOAT(size)', 'float', null, null, null, false, null, null, null, null, null, null, null, + 'https://mariadb.com/kb/en/float/', false, true), + (1, 'INT(size)', 'int', null, null, null, false, null, null, null, null, null, null, 'size in Bytes', + 'https://mariadb.com/kb/en/int/', false, true), + (1, 'LONGBLOB', 'longblob', null, null, null, null, null, null, null, null, null, null, 'max. 3.999 GiB', + 'https://mariadb.com/kb/en/longblob/', false, true), + (1, 'LONGTEXT', 'longtext', null, null, null, null, null, null, null, null, null, null, 'max. 3.999 GiB', + 'https://mariadb.com/kb/en/longtext/', true, true), + (1, 'MEDIUMBLOB', 'mediumblob', null, null, null, null, null, null, null, null, null, null, 'max. 15.999 MiB', + 'https://mariadb.com/kb/en/mediumblob/', false, true), + (1, 'MEDIUMINT', 'mediumint', null, null, null, null, null, null, null, null, null, null, 'size in Bytes', + 'https://mariadb.com/kb/en/mediumint/', false, true), + (1, 'MEDIUMTEXT', 'mediumtext', null, null, null, null, null, null, null, null, null, null, 'size in Bytes', + 'https://mariadb.com/kb/en/mediumtext/', true, true), + (1, 'SET(v1,v2,...)', 'set', null, null, null, null, null, null, null, null, null, null, null, + 'https://mariadb.com/kb/en/set/', true, true), + (1, 'SMALLINT(size)', 'smallint', 0, null, null, false, null, null, null, null, null, null, 'size in Bytes', + 'https://mariadb.com/kb/en/smallint/', false, true), + (1, 'TEXT(size)', 'text', 0, null, null, false, null, null, null, null, null, null, 'size in Bytes', + 'https://mariadb.com/kb/en/text/', true, true), + (1, 'TIME(fsp)', 'time', 0, 6, 0, false, null, null, null, null, null, null, + 'fsp=microsecond precision, min. 0, max. 6', 'https://mariadb.com/kb/en/time/', true, true), + (1, 'TIMESTAMP(fsp)', 'timestamp', 0, 6, 0, false, null, null, null, null, null, null, + 'fsp=microsecond precision, min. 0, max. 6', 'https://mariadb.com/kb/en/timestamp/', true, true), + (1, 'TINYBLOB', 'tinyblob', null, null, null, null, null, null, null, null, null, null, + 'fsp=microsecond precision, min. 0, max. 6', 'https://mariadb.com/kb/en/timestamp/', false, true), + (1, 'TINYINT(size)', 'tinyint', 0, null, null, false, null, null, null, null, null, null, + 'size in Bytes', 'https://mariadb.com/kb/en/tinyint/', false, true), + (1, 'TINYTEXT', 'tinytext', null, null, null, null, null, null, null, null, null, null, + 'max. 255 characters', 'https://mariadb.com/kb/en/tinytext/', true, true), + (1, 'YEAR', 'year', 2, 4, null, false, 2, null, null, null, null, null, 'min. 1901, max. 2155', + 'https://mariadb.com/kb/en/year/', false, true), + (1, 'VARBINARY(size)', 'varbinary', 0, null, null, true, null, null, null, null, null, null, + null, 'https://mariadb.com/kb/en/varbinary/', false, true), + (1, 'VARCHAR(size)', 'varchar', 0, 65532, 255, true, null, null, null, null, null, null, + null, 'https://mariadb.com/kb/en/varchar/', false, true); + + INSERT + INTO `mdb_ontologies` (prefix, uri, uri_pattern, sparql_endpoint, rdf_path) VALUES ('om', 'http://www.ontology-of-units-of-measure.org/resource/om-2/', 'http://www.ontology-of-units-of-measure.org/resource/om-2/.*', null, 'rdf/om-2.0.rdf'), ('wd', 'http://www.wikidata.org/', 'http://www.wikidata.org/entity/.*', 'https://query.wikidata.org/sparql', diff --git a/helm/dbrepo/templates/metadata-deployment.yaml b/helm/dbrepo/templates/metadata-deployment.yaml index 4d16efb68bc6987c71b551311d83a2bffe819be5..46c96a331d55d330054cff0d43b7e956f816762c 100644 --- a/helm/dbrepo/templates/metadata-deployment.yaml +++ b/helm/dbrepo/templates/metadata-deployment.yaml @@ -4,7 +4,7 @@ apiVersion: apps/v1 kind: Deployment metadata: name: metadata-service - namespace: {{ .Values.namespace }} + namespace: {{ include "common.names.namespace" . | quote }} labels: app: metadata-service service: metadata-service @@ -45,7 +45,7 @@ spec: - -ec - "curl -sSL localhost:8080/actuator/health/readiness | grep 'UP' || exit 1" initialDelaySeconds: 120 - periodSeconds: 30 + periodSeconds: 10 readinessProbe: exec: command: @@ -53,7 +53,7 @@ spec: - -ec - "curl -sSL localhost:8080/actuator/health/liveness | grep 'UP' || exit 1" initialDelaySeconds: 30 - periodSeconds: 30 + periodSeconds: 10 {{- if .Values.metadataservice.resources }} resources: {{- toYaml .Values.metadataservice.resources | nindent 12 }} {{- end }} diff --git a/helm/dbrepo/templates/metadata-secret.yaml b/helm/dbrepo/templates/metadata-secret.yaml index 0718b02ea1f7ed10d4a53d9d93e04ce985104bb1..684adf0269b687199b84e59623624180643bc9b9 100644 --- a/helm/dbrepo/templates/metadata-secret.yaml +++ b/helm/dbrepo/templates/metadata-secret.yaml @@ -4,7 +4,7 @@ apiVersion: v1 kind: Secret metadata: name: metadata-service-secret - namespace: {{ .Values.namespace }} + namespace: {{ include "common.names.namespace" . | quote }} stringData: ADMIN_EMAIL: "{{ .Values.metadataservice.admin.email }}" ANALYSE_SERVICE_ENDPOINT: "{{ .Values.analyseservice.endpoint }}" diff --git a/helm/dbrepo/templates/metadata-service.yaml b/helm/dbrepo/templates/metadata-service.yaml index 80482da29272d7b2de8018c120aa41c82614a75a..592108ecacf5c83137ae429005fbf6826f114483 100644 --- a/helm/dbrepo/templates/metadata-service.yaml +++ b/helm/dbrepo/templates/metadata-service.yaml @@ -4,7 +4,7 @@ apiVersion: v1 kind: Service metadata: name: metadata-service - namespace: {{ $.Values.namespace }} + namespace: {{ include "common.names.namespace" . | quote }} labels: service: metadata-service spec: diff --git a/helm/dbrepo/templates/search-deployment.yaml b/helm/dbrepo/templates/search-deployment.yaml index 6ba54abfcab317ab3d1a93ebf7589cdcbbcd81c4..40e3e89c1317ce177f9407311d66a4bb6b26e337 100644 --- a/helm/dbrepo/templates/search-deployment.yaml +++ b/helm/dbrepo/templates/search-deployment.yaml @@ -4,7 +4,7 @@ apiVersion: apps/v1 kind: Deployment metadata: name: search-service - namespace: {{ .Values.namespace }} + namespace: {{ include "common.names.namespace" . | quote }} labels: app: search-service service: search-service @@ -62,15 +62,15 @@ spec: - -ec - "curl -sSL localhost:8080/health | grep 'UP' || exit 1" initialDelaySeconds: 120 - periodSeconds: 30 + periodSeconds: 10 readinessProbe: exec: command: - /bin/bash - -ec - "curl -sSL localhost:8080/health | grep 'UP' || exit 1" - initialDelaySeconds: 10 - periodSeconds: 30 + initialDelaySeconds: 30 + periodSeconds: 10 {{- if .Values.searchservice.resources }} resources: {{- toYaml .Values.searchservice.resources | nindent 12 }} {{- end }} diff --git a/helm/dbrepo/templates/search-secret.yaml b/helm/dbrepo/templates/search-secret.yaml index 251da00248f77afa295483890064ed6a3bc73211..c4293bd7fd88a00115e57c7abd5e3b89b84724b4 100644 --- a/helm/dbrepo/templates/search-secret.yaml +++ b/helm/dbrepo/templates/search-secret.yaml @@ -4,7 +4,7 @@ apiVersion: v1 kind: Secret metadata: name: search-service-secret - namespace: {{ .Values.namespace }} + namespace: {{ include "common.names.namespace" . | quote }} stringData: ADMIN_USERNAME: "{{ .Values.identityservice.users }}" ADMIN_PASSWORD: "{{ .Values.identityservice.userPasswords }}" diff --git a/helm/dbrepo/templates/search-service.yaml b/helm/dbrepo/templates/search-service.yaml index 00eb434a7c3c9c926d68d43627a1e6b1c55bf02a..e0a31e91513cdb6c396671f44c84f56199c371f7 100644 --- a/helm/dbrepo/templates/search-service.yaml +++ b/helm/dbrepo/templates/search-service.yaml @@ -4,7 +4,7 @@ apiVersion: v1 kind: Service metadata: name: search-service - namespace: {{ $.Values.namespace }} + namespace: {{ include "common.names.namespace" . | quote }} labels: service: search-service spec: diff --git a/helm/dbrepo/templates/secret.yaml b/helm/dbrepo/templates/secret.yaml index 5761aaa774f7d7a702910dd9b7a809c7c694b171..bbd40645973c19159c2093473390f9de267735df 100644 --- a/helm/dbrepo/templates/secret.yaml +++ b/helm/dbrepo/templates/secret.yaml @@ -4,7 +4,7 @@ kind: Secret type: kubernetes.io/tls metadata: name: ingress-cert - namespace: {{ .Values.namespace }} + namespace: {{ include "common.names.namespace" . | quote }} stringData: tls.crt: | -----BEGIN CERTIFICATE----- diff --git a/helm/dbrepo/templates/storage-job.yaml b/helm/dbrepo/templates/storage-job.yaml index 4062aa8efeba0282954623e814bf4757e44a5f88..c5eb6605e28c08cfbb8fac906de1ca610705bf4a 100644 --- a/helm/dbrepo/templates/storage-job.yaml +++ b/helm/dbrepo/templates/storage-job.yaml @@ -4,7 +4,7 @@ apiVersion: batch/v1 kind: Job metadata: name: storage-service-create-buckets-job - namespace: {{ .Values.namespace }} + namespace: {{ include "common.names.namespace" . | quote }} spec: template: metadata: diff --git a/helm/dbrepo/templates/storage-secret.yaml b/helm/dbrepo/templates/storage-secret.yaml index 77bf426717fc50fe7b468196c61218388c60bf6b..3e1ed0f37df510ecbfe7b7e3a8655a0ab6ca31c3 100644 --- a/helm/dbrepo/templates/storage-secret.yaml +++ b/helm/dbrepo/templates/storage-secret.yaml @@ -4,7 +4,7 @@ apiVersion: v1 kind: Secret metadata: name: storage-service-secret - namespace: {{ .Values.namespace }} + namespace: {{ include "common.names.namespace" . | quote }} stringData: S3_BUCKET: "{{ .Values.storageservice.s3.bucket }}" config.json: | diff --git a/helm/dbrepo/templates/ui-deployment.yaml b/helm/dbrepo/templates/ui-deployment.yaml index 8c72c35f0d395230bcf3b9ace4a76a7b721bcfe7..2eed973a2aa196de26bbddc02226998706aa960c 100644 --- a/helm/dbrepo/templates/ui-deployment.yaml +++ b/helm/dbrepo/templates/ui-deployment.yaml @@ -4,7 +4,7 @@ apiVersion: apps/v1 kind: Deployment metadata: name: ui - namespace: {{ .Values.namespace }} + namespace: {{ include "common.names.namespace" . | quote }} labels: app: ui service: ui @@ -47,13 +47,13 @@ spec: path: / port: 3000 initialDelaySeconds: 120 - periodSeconds: 30 + periodSeconds: 10 readinessProbe: httpGet: path: / port: 3000 initialDelaySeconds: 30 - periodSeconds: 30 + periodSeconds: 10 {{- if .Values.ui.resources }} resources: {{- toYaml .Values.ui.resources | nindent 12 }} {{- end }} diff --git a/helm/dbrepo/templates/ui-secret.yaml b/helm/dbrepo/templates/ui-secret.yaml index af933da2e36e6af80711e46692757f4c650202f5..81fd70447a931a1cde7e8786c4d9d7f001d53e55 100644 --- a/helm/dbrepo/templates/ui-secret.yaml +++ b/helm/dbrepo/templates/ui-secret.yaml @@ -5,7 +5,7 @@ apiVersion: v1 kind: Secret metadata: name: ui-secret - namespace: {{ .Values.namespace }} + namespace: {{ include "common.names.namespace" . | quote }} stringData: NUXT_PUBLIC_API_CLIENT: "{{ .Values.ui.public.api.client | default .Values.gateway }}" NUXT_PUBLIC_API_SERVER: "{{ .Values.ui.public.api.server | default .Values.gateway }}" diff --git a/helm/dbrepo/templates/ui-service.yaml b/helm/dbrepo/templates/ui-service.yaml index 1abb5c65593b2550f4e739a3710bc8af3f33bbd7..1ec140db603c075948b18cf933e2f5f322ac6aae 100644 --- a/helm/dbrepo/templates/ui-service.yaml +++ b/helm/dbrepo/templates/ui-service.yaml @@ -4,7 +4,7 @@ apiVersion: v1 kind: Service metadata: name: ui - namespace: {{ $.Values.namespace }} + namespace: {{ include "common.names.namespace" . | quote }} labels: service: ui spec: diff --git a/helm/dbrepo/templates/upload-secret.yaml b/helm/dbrepo/templates/upload-secret.yaml index 489b99743cbaaa9a816ce4d2efe7302c4b0aa5e0..c666ea2b05d0107a97f2485ebc843493de64776b 100644 --- a/helm/dbrepo/templates/upload-secret.yaml +++ b/helm/dbrepo/templates/upload-secret.yaml @@ -4,7 +4,7 @@ apiVersion: v1 kind: Secret metadata: name: upload-service-secret - namespace: {{ .Values.namespace }} + namespace: {{ include "common.names.namespace" . | quote }} stringData: AWS_ACCESS_KEY_ID: "{{ .Values.storageservice.s3.auth.adminAccessKeyId }}" AWS_SECRET_ACCESS_KEY: "{{ .Values.storageservice.s3.auth.adminSecretAccessKey }}" diff --git a/helm/dbrepo/values.schema.json b/helm/dbrepo/values.schema.json index 843f7e799100a7b8a5041c96b8914275326ea2b7..a8e7bbbf743a45c32d8a3a43c8785f4c279fc0ba 100644 --- a/helm/dbrepo/values.schema.json +++ b/helm/dbrepo/values.schema.json @@ -132,17 +132,6 @@ }, "authservice": { "properties": { - "auth": { - "properties": { - "adminPassword": { - "type": "string" - }, - "adminUser": { - "type": "string" - } - }, - "type": "object" - }, "client": { "properties": { "id": { @@ -367,6 +356,14 @@ }, "type": "object" }, + "metrics": { + "properties": { + "enabled": { + "type": "boolean" + } + }, + "type": "object" + }, "persistence": { "properties": { "enabled": { @@ -389,6 +386,23 @@ }, "service": { "properties": { + "extraPorts": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "port": { + "type": "integer" + }, + "targetPort": { + "type": "integer" + } + }, + "type": "object" + }, + "type": "array" + }, "managerPortEnabled": { "type": "boolean" }, @@ -407,37 +421,9 @@ "clusterDomain": { "type": "string" }, - "datadb": { + "dashboardservice": { "properties": { - "auth": { - "properties": { - "replicationPassword": { - "type": "string" - }, - "replicationUser": { - "type": "string" - }, - "rootPassword": { - "type": "string" - } - }, - "type": "object" - }, - "enabled": { - "type": "boolean" - }, - "fullnameOverride": { - "type": "string" - }, - "image": { - "properties": { - "debug": { - "type": "boolean" - } - }, - "type": "object" - }, - "metrics": { + "dashboardsProvider": { "properties": { "enabled": { "type": "boolean" @@ -445,61 +431,27 @@ }, "type": "object" }, - "primary": { + "datasources": { "properties": { - "extraVolumeMounts": { - "items": { - "properties": { - "mountPath": { - "type": "string" - }, - "name": { - "type": "string" - } - }, - "type": "object" - }, - "type": "array" - }, - "extraVolumes": { - "items": { - "properties": { - "emptyDir": { - "properties": {}, - "type": "object" - }, - "name": { - "type": "string" - } - }, - "type": "object" - }, - "type": "array" - }, - "persistence": { + "secretDefinition": { "properties": { - "enabled": { - "type": "boolean" - } - }, - "type": "object" - }, - "service": { - "properties": { - "extraPorts": { + "apiVersion": { + "type": "integer" + }, + "datasources": { "items": { "properties": { "name": { "type": "string" }, - "port": { - "type": "integer" + "type": { + "type": "string" }, - "protocol": { + "uid": { "type": "string" }, - "targetPort": { - "type": "integer" + "url": { + "type": "string" } }, "type": "object" @@ -508,161 +460,108 @@ } }, "type": "object" - }, - "sidecars": { + } + }, + "type": "object" + }, + "enabled": { + "type": "boolean" + }, + "fullnameOverride": { + "type": "string" + }, + "grafana": { + "properties": { + "extraConfigmaps": { "items": { "properties": { - "envFrom": { - "items": { - "properties": { - "secretRef": { - "properties": { - "name": { - "type": "string" - } - }, - "type": "object" - } - }, - "type": "object" - }, - "type": "array" - }, - "image": { - "type": "string" - }, - "imagePullPolicy": { + "mountPath": { "type": "string" }, - "livenessProbe": { - "properties": { - "exec": { - "properties": { - "command": { - "items": { - "type": "string" - }, - "type": "array" - } - }, - "type": "object" - }, - "initialDelaySeconds": { - "type": "integer" - }, - "periodSeconds": { - "type": "integer" - } - }, - "type": "object" - }, "name": { "type": "string" }, - "ports": { - "items": { - "properties": { - "containerPort": { - "type": "integer" - }, - "name": { - "type": "string" - }, - "protocol": { - "type": "string" - } - }, - "type": "object" - }, - "type": "array" - }, - "readinessProbe": { - "properties": { - "exec": { - "properties": { - "command": { - "items": { - "type": "string" - }, - "type": "array" - } - }, - "type": "object" - }, - "initialDelaySeconds": { - "type": "integer" - }, - "periodSeconds": { - "type": "integer" - } - }, - "type": "object" - }, - "securityContext": { - "properties": { - "allowPrivilegeEscalation": { - "type": "boolean" - }, - "capabilities": { - "properties": { - "drop": { - "items": { - "type": "string" - }, - "type": "array" - } - }, - "type": "object" - }, - "runAsGroup": { - "type": "integer" - }, - "runAsNonRoot": { - "type": "boolean" - }, - "runAsUser": { - "type": "integer" - }, - "seccompProfile": { - "properties": { - "type": { - "type": "string" - } - }, - "type": "object" - } - }, - "type": "object" - }, - "volumeMounts": { - "items": { - "properties": { - "mountPath": { - "type": "string" - }, - "name": { - "type": "string" - } - }, - "type": "object" - }, - "type": "array" + "readOnly": { + "type": "boolean" } }, "type": "object" }, "type": "array" + }, + "extraEnvVarsSecret": { + "type": "string" } }, "type": "object" }, - "secondary": { + "ldap": { "properties": { - "replicaCount": { - "type": "integer" + "allowSignUp": { + "type": "boolean" + }, + "enabled": { + "type": "boolean" + }, + "secretName": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "datadb": { + "properties": { + "database": { + "properties": { + "auth": { + "properties": { + "replicationPassword": { + "type": "string" + }, + "replicationUser": { + "type": "string" + }, + "rootPassword": { + "type": "string" + } + }, + "type": "object" + }, + "image": { + "properties": { + "debug": { + "type": "boolean" + } + }, + "type": "object" + }, + "metrics": { + "properties": { + "enabled": { + "type": "boolean" + } + }, + "type": "object" + }, + "secondary": { + "properties": { + "replicaCount": { + "type": "integer" + } + }, + "type": "object" } }, "type": "object" + }, + "enabled": { + "type": "boolean" + }, + "fullnameOverride": { + "type": "string" } }, "type": "object" @@ -1042,6 +941,10 @@ "enabled": { "type": "boolean" }, + "extraInitDbScripts": { + "properties": {}, + "type": "object" + }, "fullnameOverride": { "type": "string" }, @@ -1064,10 +967,6 @@ "host": { "type": "string" }, - "initdbScripts": { - "properties": {}, - "type": "object" - }, "initdbScriptsConfigMap": { "type": "string" }, @@ -1311,8 +1210,78 @@ }, "type": "object" }, - "namespace": { - "type": "string" + "metricdb": { + "properties": { + "alertmanager": { + "properties": { + "service": { + "properties": { + "type": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "enabled": { + "type": "boolean" + }, + "fullnameOverride": { + "type": "string" + }, + "server": { + "properties": { + "extraScrapeConfigs": { + "items": { + "properties": { + "job_name": { + "type": "string" + }, + "metrics_path": { + "type": "string" + }, + "static_configs": { + "items": { + "properties": { + "targets": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "type": "array" + }, + "persistence": { + "properties": { + "enabled": { + "type": "boolean" + } + }, + "type": "object" + }, + "service": { + "properties": { + "type": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + } + }, + "type": "object" }, "searchdb": { "properties": { @@ -1333,12 +1302,6 @@ }, "security": { "properties": { - "adminPassword": { - "type": "string" - }, - "adminUsername": { - "type": "string" - }, "enabled": { "type": "boolean" } @@ -1517,6 +1480,14 @@ }, "mariadb": { "properties": { + "auth": { + "properties": { + "rootPassword": { + "type": "string" + } + }, + "type": "object" + }, "enabled": { "type": "boolean" }, @@ -1530,6 +1501,14 @@ "properties": { "enabled": { "type": "boolean" + }, + "metrics": { + "properties": { + "enabled": { + "type": "boolean" + } + }, + "type": "object" } }, "type": "object" diff --git a/helm/dbrepo/values.yaml b/helm/dbrepo/values.yaml index af810436af63b6ca3b87a08c767a28959852ec35..68c2e4e06fed820f6c5858efdce9bcf97550fada 100644 --- a/helm/dbrepo/values.yaml +++ b/helm/dbrepo/values.yaml @@ -15,8 +15,6 @@ global: ## @section Common parameters -## @param namespace The namespace to install the chart -namespace: dbrepo ## @param hostname The hostname. hostname: example.com ## @param gateway The gateway endpoint. @@ -53,7 +51,7 @@ metadatadb: jdbcExtraArgs: "" metrics: ## @skip metadatadb.metrics.enabled The Prometheus settings. - enabled: false + enabled: true ## @skip metadatadb.initdbScriptsConfigMap The initial database scripts. initdbScriptsConfigMap: metadata-db-setup ## @param metadatadb.extraInitDbScripts Additional init.db scripts that are executed on the first start. @@ -100,8 +98,8 @@ authservice: ## @skip authservice.tls.usePem usePem: true metrics: - ## @param authservice.metrics.enabled Enable the Prometheus metrics export sidecar container. - enabled: false + ## @skip authservice.metrics.enabled + enabled: true client: ## @param authservice.client.id The client id for the microservices. id: dbrepo-client @@ -128,78 +126,23 @@ datadb: enabled: true ## @skip datadb.fullnameOverride fullnameOverride: data-db - image: - ## @param datadb.image.debug Set the logging level to `trace`. Otherwise, set to `info`. - debug: false - auth: - ## @param datadb.auth.rootPassword The root user password. - rootPassword: dbrepo - ## @param datadb.auth.replicationUser The database replication user password - replicationUser: replication - ## @param datadb.auth.replicationPassword The database replication user password - replicationPassword: replication - metrics: - ## @skip datadb.metrics.enabled - enabled: true - ## @skip datadb.primary - primary: - service: - extraPorts: - - name: "sidecar" - port: 8080 - targetPort: 8080 - protocol: TCP - sidecars: - - name: sidecar - image: registry.datalab.tuwien.ac.at/dbrepo/data-db-sidecar:1.4.5 - imagePullPolicy: Always - securityContext: - runAsUser: 1001 - runAsGroup: 0 - runAsNonRoot: true - allowPrivilegeEscalation: false - seccompProfile: - type: RuntimeDefault - capabilities: - drop: - - ALL - ports: - - name: "sidecar" - containerPort: 8080 - protocol: TCP - envFrom: - - secretRef: - name: data-service-secret - livenessProbe: - exec: - command: - - /bin/bash - - -ec - - "curl -sSL localhost:8080/health | grep 'UP' || exit 1" - initialDelaySeconds: 120 - periodSeconds: 30 - readinessProbe: - exec: - command: - - /bin/bash - - -ec - - "curl -sSL localhost:8080/health | grep 'UP' || exit 1" - initialDelaySeconds: 30 - periodSeconds: 30 - volumeMounts: - - name: s3 - mountPath: /s3 - extraVolumeMounts: - - name: s3 - mountPath: /s3 - extraVolumes: - - name: s3 - emptyDir: { } - persistence: + database: + image: + ## @param datadb.database.image.debug Set the logging level to `trace`. Otherwise, set to `info`. + debug: false + metrics: + ## @skip datadb.database.metrics.enabled enabled: true - ## @skip datadb.secondary - secondary: - replicaCount: 2 + ## @skip datadb.database.secondary + secondary: + replicaCount: 2 + auth: + ## @param datadb.auth.rootPassword The root user password. + rootPassword: dbrepo + ## @param datadb.auth.replicationUser The database replication user password + replicationUser: replication + ## @param datadb.auth.replicationPassword The database replication user password + replicationPassword: replication ## @section Search Database @@ -266,6 +209,9 @@ brokerservice: image: ## @param brokerservice.image.debug Set the logging level to `trace`. Otherwise, set to `info`. debug: true + metrics: + ## @skip brokerservice.metrics.enabled + enabled: true ## @param brokerservice.endpoint The management api endpoint for the microservices. endpoint: http://broker-service:15672 ## @param brokerservice.host The hostname for the microservices. @@ -316,7 +262,7 @@ brokerservice: enabled: true existingSecret: broker-service-secret ## @param brokerservice.extraPlugins The list of plugins to be activated. - extraPlugins: rabbitmq_prometheus rabbitmq_auth_backend_ldap rabbitmq_auth_mechanism_ssl + extraPlugins: rabbitmq_prometheus rabbitmq_auth_backend_ldap rabbitmq_auth_mechanism_ssl rabbitmq_mqtt persistence: ## @param brokerservice.persistence.enabled If set to true, a PVC will be created. enabled: false @@ -324,6 +270,10 @@ brokerservice: service: type: ClusterIP managerPortEnabled: true + extraPorts: + - name: mqtt + port: 1883 + targetPort: 1883 # loadBalancerIP: ## @param brokerservice.replicaCount The number of replicas. replicaCount: 1 @@ -335,7 +285,7 @@ analyseservice: enabled: true image: ## @skip analyseservice.image.name - name: registry.datalab.tuwien.ac.at/dbrepo/analyse-service:1.4.5 + name: registry.datalab.tuwien.ac.at/dbrepo/analyse-service:1.4.7 ## @skip analyseservice.image.pullPolicy pullPolicy: Always ## @param analyseservice.image.debug Set the logging level to `trace`. Otherwise, set to `info`. @@ -397,7 +347,7 @@ metadataservice: enabled: true image: ## @skip metadataservice.image.name - name: registry.datalab.tuwien.ac.at/dbrepo/metadata-service:1.4.5 + name: registry.datalab.tuwien.ac.at/dbrepo/metadata-service:1.4.7 ## @skip metadataservice.image.pullPolicy pullPolicy: Always ## @param metadataservice.image.debug Set the logging level to `trace`. Otherwise, set to `info`. @@ -496,7 +446,7 @@ dataservice: endpoint: http://data-service image: ## @skip dataservice.image.name - name: registry.datalab.tuwien.ac.at/dbrepo/data-service:1.4.5 + name: registry.datalab.tuwien.ac.at/dbrepo/data-service:1.4.7 ## @skip dataservice.image.pullPolicy pullPolicy: Always ## @param dataservice.image.debug Set the logging level to `trace`. Otherwise, set to `info`. @@ -583,7 +533,7 @@ searchservice: endpoint: http://search-service image: ## @skip searchservice.image.name - name: registry.datalab.tuwien.ac.at/dbrepo/search-service:1.4.5 + name: registry.datalab.tuwien.ac.at/dbrepo/search-service:1.4.7 ## @skip searchservice.image.pullPolicy pullPolicy: Always ## @param searchservice.image.debug Set the logging level to `trace`. Otherwise, set to `info`. @@ -632,7 +582,7 @@ searchservice: ## @skip searchservice.init init: image: - name: registry.datalab.tuwien.ac.at/dbrepo/search-service-init:1.4.5 + name: registry.datalab.tuwien.ac.at/dbrepo/search-service-init:1.4.7 pullPolicy: Always ## @param searchservice.replicaCount The number of replicas. replicaCount: 2 @@ -649,9 +599,15 @@ storageservice: fullnameOverride: storage-service-db ## @skip storageservice.mariadb.enabled enabled: true + auth: + ## @param storageservice.mariadb.auth.rootPassword The user password for the root user. + rootPassword: seaweedfsdb master: ## @skip storageservice.master.enabled enabled: true + metrics: + ## @skip storageservice.master.metrics.enabled + enabled: true filer: ## @param storageservice.filer.enabled Enable the storage service filer which is required for S3. enabled: true @@ -674,7 +630,7 @@ storageservice: adminSecretAccessKey: seaweedfsadmin ## @skip storageservice.init init: - image: registry.datalab.tuwien.ac.at/dbrepo/storage-service-init:1.4.5 + image: registry.datalab.tuwien.ac.at/dbrepo/storage-service-init:1.4.7 pullPolicy: Always ## @section Identity Service @@ -737,7 +693,7 @@ ui: enabled: true image: ## @skip ui.image.name - name: registry.datalab.tuwien.ac.at/dbrepo/ui:1.4.5 + name: registry.datalab.tuwien.ac.at/dbrepo/ui:1.4.7 ## @skip ui.image.pullPolicy pullPolicy: Always ## @param ui.image.debug Set the logging level to `trace`. Otherwise, set to `info`. @@ -843,6 +799,74 @@ ui: # mountPath: /static/logo.svg # subPath: logo.svg +## @section Dashboard Service + +dashboardservice: + ## @param dashboardservice.enabled Enable the Dashboard Service. + enabled: true + ## @skip dashboardservice.fullnameOverride + fullnameOverride: dashboard-service + ldap: + ## @skip dashboardservice.ldap.enabled + enabled: true + ## @skip dashboardservice.ldap.allowSignUp + allowSignUp: true + ## @skip dashboardservice.ldap.secretName + secretName: dashboard-service-secret + grafana: + ## @skip dashboardservice.grafana.extraEnvVarsSecret + extraEnvVarsSecret: dashboard-service-secret + ## @skip dashboardservice.grafana.extraConfigmaps + extraConfigmaps: + - name: dashboard-service-config + mountPath: /opt/bitnami/grafana/dashboards + readOnly: true + datasources: + ## @skip dashboardservice.datasources.secretDefinition + secretDefinition: + apiVersion: 1 + datasources: + - name: "dbrepo-metric-db" + uid: "P18F45E9DC7E75912" + type: "prometheus" + url: "http://metric-db-server" + dashboardsProvider: + ## @param dashboardservice.dashboardsProvider.enabled Enable the default dashboard provisioning provider to routinely import dashboards from /opt/bitnami/grafana/dashboards + enabled: true + +## @section Metric Service + +metricdb: + ## @param metricdb.enabled Enable the Metric Service. + enabled: true + ## @skip metricdb.fullnameOverride + fullnameOverride: metric-db + alertmanager: + service: + ## @skip metricdb.alertmanager.service.type + type: ClusterIP + server: + service: + ## @skip metricdb.server.service.type + type: ClusterIP + persistence: + ## @skip metricdb.server.persistence.enabled + enabled: true + ## @skip metricdb.server.extraScrapeConfigs + extraScrapeConfigs: + - job_name: 'actuator scrape' + metrics_path: '/actuator/prometheus' + static_configs: + - targets: [ 'data-service', 'metadata-service', 'ui' ] + - job_name: 'metrics scrape' + metrics_path: '/metrics' + static_configs: + - targets: [ 'auth-service-metrics:8080', 'analyse-service', 'search-service', 'data-db:8080', 'data-db-metrics:9104', 'broker-service:9419', 'metadata-db-metrics:9104', 'storage-service-master-metrics:9327', 'upload-service' ] + - job_name: 'dashboard scrape' + metrics_path: '/dashboard/metrics' + static_configs: + - targets: [ 'dashboard-service:3000' ] + ## @section Ingress ingress: diff --git a/install.sh b/install.sh index 5e367f4d53fefc633fb3131dad7360569ea971ac..03974502c259f964cd22a8bd5f5f2ec983635c71 100644 --- a/install.sh +++ b/install.sh @@ -1,9 +1,9 @@ #!/bin/bash # preset -VERSION="1.4.5" +VERSION="1.4.7" MIN_CPU=8 -MIN_RAM=8 +MIN_RAM=4 MIN_MAP_COUNT=262144 SKIP_CHECKS=${SKIP_CHECKS:-0} DOWNLOAD_ONLY=${DOWNLOAD_ONLY:-0} @@ -58,7 +58,7 @@ fi # environment echo "[🚀] Gathering environment for version ${VERSION} ..." -curl -sSL -o ./dist.tar.gz "https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/raw/release-${VERSION}/.docker/dist.tar.gz" +curl -ksSL -o ./dist.tar.gz "https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/${VERSION}/dist.tar.gz" tar xzfv ./dist.tar.gz if [[ $DOWNLOAD_ONLY -eq 1 ]]; then diff --git a/lib/python/.coveragerc b/lib/python/.coveragerc new file mode 100644 index 0000000000000000000000000000000000000000..2301243c8400da8046858a8cbfc8a5abfad9b5d7 --- /dev/null +++ b/lib/python/.coveragerc @@ -0,0 +1,3 @@ +[report] +omit = + */tests/* diff --git a/lib/python/.gitignore b/lib/python/.gitignore index 46916e3e91c948d297fa8fda068bc1b123d9aced..c954a774008e444617bea9ec16df30b7dda3183b 100644 --- a/lib/python/.gitignore +++ b/lib/python/.gitignore @@ -5,6 +5,7 @@ dist/ dbrepo.egg-info/ build/ +htmlcov/ # debug debug.py diff --git a/lib/python/Makefile b/lib/python/Makefile index 229fa04db39df9ca8d20263cf3777b8b79e1febe..afebb199acc957c9972a89535b90052f510edbb5 100644 --- a/lib/python/Makefile +++ b/lib/python/Makefile @@ -1,4 +1,4 @@ -all: build install +all: build clean: rm -rf ./python/dist/* ./docs/build/* ./dist/* @@ -14,14 +14,6 @@ build: clean python3 -m build --sdist . python3 -m build --wheel . -install: - cp ./dist/dbrepo-* ../../dbrepo-analyse-service/lib/ - (cd ../../dbrepo-analyse-service && pipenv lock) - cp ./dist/dbrepo-* ../../dbrepo-search-service/lib/ - (cd ../../dbrepo-search-service && pipenv lock) - cp ./dist/dbrepo-* ../../dbrepo-search-service/init/lib/ - (cd ../../dbrepo-search-service/init && pipenv lock) - deploy: build python3 -m twine upload --config-file ~/.pypirc --verbose --repository pypi ./dist/dbrepo-* diff --git a/lib/python/Pipfile.lock b/lib/python/Pipfile.lock index 953bcf20f326a8e1fc3c313683f09d546271f963..fd2af13e692cfbe941701b905d22f00e6b14064c 100644 --- a/lib/python/Pipfile.lock +++ b/lib/python/Pipfile.lock @@ -16,87 +16,110 @@ ] }, "default": { + "aiohappyeyeballs": { + "hashes": [ + "sha256:75cf88a15106a5002a8eb1dab212525c00d1f4c0fa96e551c9fbe6f09a621586", + "sha256:8a7a83727b2756f394ab2895ea0765a0a8c475e3c71e98d43d76f22b4b435572" + ], + "markers": "python_version >= '3.8'", + "version": "==2.4.3" + }, "aiohttp": { "hashes": [ - "sha256:0605cc2c0088fcaae79f01c913a38611ad09ba68ff482402d3410bf59039bfb8", - "sha256:0a158704edf0abcac8ac371fbb54044f3270bdbc93e254a82b6c82be1ef08f3c", - "sha256:0cbf56238f4bbf49dab8c2dc2e6b1b68502b1e88d335bea59b3f5b9f4c001475", - "sha256:1732102949ff6087589408d76cd6dea656b93c896b011ecafff418c9661dc4ed", - "sha256:18f634d540dd099c262e9f887c8bbacc959847cfe5da7a0e2e1cf3f14dbf2daf", - "sha256:239f975589a944eeb1bad26b8b140a59a3a320067fb3cd10b75c3092405a1372", - "sha256:2faa61a904b83142747fc6a6d7ad8fccff898c849123030f8e75d5d967fd4a81", - "sha256:320e8618eda64e19d11bdb3bd04ccc0a816c17eaecb7e4945d01deee2a22f95f", - "sha256:38d80498e2e169bc61418ff36170e0aad0cd268da8b38a17c4cf29d254a8b3f1", - "sha256:3916c8692dbd9d55c523374a3b8213e628424d19116ac4308e434dbf6d95bbdd", - "sha256:393c7aba2b55559ef7ab791c94b44f7482a07bf7640d17b341b79081f5e5cd1a", - "sha256:3b7b30258348082826d274504fbc7c849959f1989d86c29bc355107accec6cfb", - "sha256:3fcb4046d2904378e3aeea1df51f697b0467f2aac55d232c87ba162709478c46", - "sha256:4109adee842b90671f1b689901b948f347325045c15f46b39797ae1bf17019de", - "sha256:4558e5012ee03d2638c681e156461d37b7a113fe13970d438d95d10173d25f78", - "sha256:45731330e754f5811c314901cebdf19dd776a44b31927fa4b4dbecab9e457b0c", - "sha256:4715a9b778f4293b9f8ae7a0a7cef9829f02ff8d6277a39d7f40565c737d3771", - "sha256:471f0ef53ccedec9995287f02caf0c068732f026455f07db3f01a46e49d76bbb", - "sha256:4d3ebb9e1316ec74277d19c5f482f98cc65a73ccd5430540d6d11682cd857430", - "sha256:4ff550491f5492ab5ed3533e76b8567f4b37bd2995e780a1f46bca2024223233", - "sha256:52c27110f3862a1afbcb2af4281fc9fdc40327fa286c4625dfee247c3ba90156", - "sha256:55b39c8684a46e56ef8c8d24faf02de4a2b2ac60d26cee93bc595651ff545de9", - "sha256:5a7ee16aab26e76add4afc45e8f8206c95d1d75540f1039b84a03c3b3800dd59", - "sha256:5ca51eadbd67045396bc92a4345d1790b7301c14d1848feaac1d6a6c9289e888", - "sha256:5d6b3f1fabe465e819aed2c421a6743d8debbde79b6a8600739300630a01bf2c", - "sha256:60cdbd56f4cad9f69c35eaac0fbbdf1f77b0ff9456cebd4902f3dd1cf096464c", - "sha256:6380c039ec52866c06d69b5c7aad5478b24ed11696f0e72f6b807cfb261453da", - "sha256:639d0042b7670222f33b0028de6b4e2fad6451462ce7df2af8aee37dcac55424", - "sha256:66331d00fb28dc90aa606d9a54304af76b335ae204d1836f65797d6fe27f1ca2", - "sha256:67c3119f5ddc7261d47163ed86d760ddf0e625cd6246b4ed852e82159617b5fb", - "sha256:694d828b5c41255e54bc2dddb51a9f5150b4eefa9886e38b52605a05d96566e8", - "sha256:6ae79c1bc12c34082d92bf9422764f799aee4746fd7a392db46b7fd357d4a17a", - "sha256:702e2c7c187c1a498a4e2b03155d52658fdd6fda882d3d7fbb891a5cf108bb10", - "sha256:714d4e5231fed4ba2762ed489b4aec07b2b9953cf4ee31e9871caac895a839c0", - "sha256:7b179eea70833c8dee51ec42f3b4097bd6370892fa93f510f76762105568cf09", - "sha256:7f64cbd44443e80094309875d4f9c71d0401e966d191c3d469cde4642bc2e031", - "sha256:82a6a97d9771cb48ae16979c3a3a9a18b600a8505b1115cfe354dfb2054468b4", - "sha256:84dabd95154f43a2ea80deffec9cb44d2e301e38a0c9d331cc4aa0166fe28ae3", - "sha256:8676e8fd73141ded15ea586de0b7cda1542960a7b9ad89b2b06428e97125d4fa", - "sha256:88e311d98cc0bf45b62fc46c66753a83445f5ab20038bcc1b8a1cc05666f428a", - "sha256:8b4f72fbb66279624bfe83fd5eb6aea0022dad8eec62b71e7bf63ee1caadeafe", - "sha256:8c64a6dc3fe5db7b1b4d2b5cb84c4f677768bdc340611eca673afb7cf416ef5a", - "sha256:8cf142aa6c1a751fcb364158fd710b8a9be874b81889c2bd13aa8893197455e2", - "sha256:8d1964eb7617907c792ca00b341b5ec3e01ae8c280825deadbbd678447b127e1", - "sha256:93e22add827447d2e26d67c9ac0161756007f152fdc5210277d00a85f6c92323", - "sha256:9c69e77370cce2d6df5d12b4e12bdcca60c47ba13d1cbbc8645dd005a20b738b", - "sha256:9dbc053ac75ccc63dc3a3cc547b98c7258ec35a215a92bd9f983e0aac95d3d5b", - "sha256:9e3a1ae66e3d0c17cf65c08968a5ee3180c5a95920ec2731f53343fac9bad106", - "sha256:a6ea1a5b409a85477fd8e5ee6ad8f0e40bf2844c270955e09360418cfd09abac", - "sha256:a81b1143d42b66ffc40a441379387076243ef7b51019204fd3ec36b9f69e77d6", - "sha256:ad7f2919d7dac062f24d6f5fe95d401597fbb015a25771f85e692d043c9d7832", - "sha256:afc52b8d969eff14e069a710057d15ab9ac17cd4b6753042c407dcea0e40bf75", - "sha256:b3df71da99c98534be076196791adca8819761f0bf6e08e07fd7da25127150d6", - "sha256:c088c4d70d21f8ca5c0b8b5403fe84a7bc8e024161febdd4ef04575ef35d474d", - "sha256:c26959ca7b75ff768e2776d8055bf9582a6267e24556bb7f7bd29e677932be72", - "sha256:c413016880e03e69d166efb5a1a95d40f83d5a3a648d16486592c49ffb76d0db", - "sha256:c6021d296318cb6f9414b48e6a439a7f5d1f665464da507e8ff640848ee2a58a", - "sha256:c671dc117c2c21a1ca10c116cfcd6e3e44da7fcde37bf83b2be485ab377b25da", - "sha256:c7a4b7a6cf5b6eb11e109a9755fd4fda7d57395f8c575e166d363b9fc3ec4678", - "sha256:c8a02fbeca6f63cb1f0475c799679057fc9268b77075ab7cf3f1c600e81dd46b", - "sha256:cd2adf5c87ff6d8b277814a28a535b59e20bfea40a101db6b3bdca7e9926bc24", - "sha256:d1469f228cd9ffddd396d9948b8c9cd8022b6d1bf1e40c6f25b0fb90b4f893ed", - "sha256:d153f652a687a8e95ad367a86a61e8d53d528b0530ef382ec5aaf533140ed00f", - "sha256:d5ab8e1f6bee051a4bf6195e38a5c13e5e161cb7bad83d8854524798bd9fcd6e", - "sha256:da00da442a0e31f1c69d26d224e1efd3a1ca5bcbf210978a2ca7426dfcae9f58", - "sha256:da22dab31d7180f8c3ac7c7635f3bcd53808f374f6aa333fe0b0b9e14b01f91a", - "sha256:e0ae53e33ee7476dd3d1132f932eeb39bf6125083820049d06edcdca4381f342", - "sha256:e7a6a8354f1b62e15d48e04350f13e726fa08b62c3d7b8401c0a1314f02e3558", - "sha256:e9a3d838441bebcf5cf442700e3963f58b5c33f015341f9ea86dcd7d503c07e2", - "sha256:edea7d15772ceeb29db4aff55e482d4bcfb6ae160ce144f2682de02f6d693551", - "sha256:f22eb3a6c1080d862befa0a89c380b4dafce29dc6cd56083f630073d102eb595", - "sha256:f26383adb94da5e7fb388d441bf09c61e5e35f455a3217bfd790c6b6bc64b2ee", - "sha256:f3c2890ca8c59ee683fd09adf32321a40fe1cf164e3387799efb2acebf090c11", - "sha256:f64fd07515dad67f24b6ea4a66ae2876c01031de91c93075b8093f07c0a2d93d", - "sha256:fcde4c397f673fdec23e6b05ebf8d4751314fa7c24f93334bf1f1364c1c69ac7", - "sha256:ff84aeb864e0fac81f676be9f4685f0527b660f1efdc40dcede3c251ef1e867f" + "sha256:02d1d6610588bcd743fae827bd6f2e47e0d09b346f230824b4c6fb85c6065f9c", + "sha256:03690541e4cc866eef79626cfa1ef4dd729c5c1408600c8cb9e12e1137eed6ab", + "sha256:0bc059ecbce835630e635879f5f480a742e130d9821fbe3d2f76610a6698ee25", + "sha256:0c21c82df33b264216abffff9f8370f303dab65d8eee3767efbbd2734363f677", + "sha256:1298b854fd31d0567cbb916091be9d3278168064fca88e70b8468875ef9ff7e7", + "sha256:1321658f12b6caffafdc35cfba6c882cb014af86bef4e78c125e7e794dfb927b", + "sha256:143b0026a9dab07a05ad2dd9e46aa859bffdd6348ddc5967b42161168c24f857", + "sha256:16e6a51d8bc96b77f04a6764b4ad03eeef43baa32014fce71e882bd71302c7e4", + "sha256:172ad884bb61ad31ed7beed8be776eb17e7fb423f1c1be836d5cb357a096bf12", + "sha256:17c272cfe7b07a5bb0c6ad3f234e0c336fb53f3bf17840f66bd77b5815ab3d16", + "sha256:1a0ee6c0d590c917f1b9629371fce5f3d3f22c317aa96fbdcce3260754d7ea21", + "sha256:2746d8994ebca1bdc55a1e998feff4e94222da709623bb18f6e5cfec8ec01baf", + "sha256:2914caa46054f3b5ff910468d686742ff8cff54b8a67319d75f5d5945fd0a13d", + "sha256:2bbf94d4a0447705b7775417ca8bb8086cc5482023a6e17cdc8f96d0b1b5aba6", + "sha256:2bd9f3eac515c16c4360a6a00c38119333901b8590fe93c3257a9b536026594d", + "sha256:2c33fa6e10bb7ed262e3ff03cc69d52869514f16558db0626a7c5c61dde3c29f", + "sha256:2d37f4718002863b82c6f391c8efd4d3a817da37030a29e2682a94d2716209de", + "sha256:3668d0c2a4d23fb136a753eba42caa2c0abbd3d9c5c87ee150a716a16c6deec1", + "sha256:36d4fba838be5f083f5490ddd281813b44d69685db910907636bc5dca6322316", + "sha256:40ff5b7660f903dc587ed36ef08a88d46840182d9d4b5694e7607877ced698a1", + "sha256:42775de0ca04f90c10c5c46291535ec08e9bcc4756f1b48f02a0657febe89b10", + "sha256:482c85cf3d429844396d939b22bc2a03849cb9ad33344689ad1c85697bcba33a", + "sha256:4e6cb75f8ddd9c2132d00bc03c9716add57f4beff1263463724f6398b813e7eb", + "sha256:4edc3fd701e2b9a0d605a7b23d3de4ad23137d23fc0dbab726aa71d92f11aaaf", + "sha256:4fd16b30567c5b8e167923be6e027eeae0f20cf2b8a26b98a25115f28ad48ee0", + "sha256:5002a02c17fcfd796d20bac719981d2fca9c006aac0797eb8f430a58e9d12431", + "sha256:51d0a4901b27272ae54e42067bc4b9a90e619a690b4dc43ea5950eb3070afc32", + "sha256:558b3d223fd631ad134d89adea876e7fdb4c93c849ef195049c063ada82b7d08", + "sha256:5c070430fda1a550a1c3a4c2d7281d3b8cfc0c6715f616e40e3332201a253067", + "sha256:5f392ef50e22c31fa49b5a46af7f983fa3f118f3eccb8522063bee8bfa6755f8", + "sha256:60555211a006d26e1a389222e3fab8cd379f28e0fbf7472ee55b16c6c529e3a6", + "sha256:608cecd8d58d285bfd52dbca5b6251ca8d6ea567022c8a0eaae03c2589cd9af9", + "sha256:60ad5b8a7452c0f5645c73d4dad7490afd6119d453d302cd5b72b678a85d6044", + "sha256:63649309da83277f06a15bbdc2a54fbe75efb92caa2c25bb57ca37762789c746", + "sha256:6ebdc3b3714afe1b134b3bbeb5f745eed3ecbcff92ab25d80e4ef299e83a5465", + "sha256:6f3c6648aa123bcd73d6f26607d59967b607b0da8ffcc27d418a4b59f4c98c7c", + "sha256:7003f33f5f7da1eb02f0446b0f8d2ccf57d253ca6c2e7a5732d25889da82b517", + "sha256:776e9f3c9b377fcf097c4a04b241b15691e6662d850168642ff976780609303c", + "sha256:85711eec2d875cd88c7eb40e734c4ca6d9ae477d6f26bd2b5bb4f7f60e41b156", + "sha256:87d1e4185c5d7187684d41ebb50c9aeaaaa06ca1875f4c57593071b0409d2444", + "sha256:8a3f063b41cc06e8d0b3fcbbfc9c05b7420f41287e0cd4f75ce0a1f3d80729e6", + "sha256:8b3fb28a9ac8f2558760d8e637dbf27aef1e8b7f1d221e8669a1074d1a266bb2", + "sha256:8bd9125dd0cc8ebd84bff2be64b10fdba7dc6fd7be431b5eaf67723557de3a31", + "sha256:8be1a65487bdfc285bd5e9baf3208c2132ca92a9b4020e9f27df1b16fab998a9", + "sha256:8cc0d13b4e3b1362d424ce3f4e8c79e1f7247a00d792823ffd640878abf28e56", + "sha256:8d9d10d10ec27c0d46ddaecc3c5598c4db9ce4e6398ca872cdde0525765caa2f", + "sha256:8debb45545ad95b58cc16c3c1cc19ad82cffcb106db12b437885dbee265f0ab5", + "sha256:91aa966858593f64c8a65cdefa3d6dc8fe3c2768b159da84c1ddbbb2c01ab4ef", + "sha256:9331dd34145ff105177855017920dde140b447049cd62bb589de320fd6ddd582", + "sha256:99f9678bf0e2b1b695e8028fedac24ab6770937932eda695815d5a6618c37e04", + "sha256:9fdf5c839bf95fc67be5794c780419edb0dbef776edcfc6c2e5e2ffd5ee755fa", + "sha256:a14e4b672c257a6b94fe934ee62666bacbc8e45b7876f9dd9502d0f0fe69db16", + "sha256:a19caae0d670771ea7854ca30df76f676eb47e0fd9b2ee4392d44708f272122d", + "sha256:a35ed3d03910785f7d9d6f5381f0c24002b2b888b298e6f941b2fc94c5055fcd", + "sha256:a61df62966ce6507aafab24e124e0c3a1cfbe23c59732987fc0fd0d71daa0b88", + "sha256:a6e00c8a92e7663ed2be6fcc08a2997ff06ce73c8080cd0df10cc0321a3168d7", + "sha256:ac3196952c673822ebed8871cf8802e17254fff2a2ed4835d9c045d9b88c5ec7", + "sha256:ac74e794e3aee92ae8f571bfeaa103a141e409863a100ab63a253b1c53b707eb", + "sha256:ad3675c126f2a95bde637d162f8231cff6bc0bc9fbe31bd78075f9ff7921e322", + "sha256:aeebd3061f6f1747c011e1d0b0b5f04f9f54ad1a2ca183e687e7277bef2e0da2", + "sha256:ba1a599255ad6a41022e261e31bc2f6f9355a419575b391f9655c4d9e5df5ff5", + "sha256:bbdb8def5268f3f9cd753a265756f49228a20ed14a480d151df727808b4531dd", + "sha256:c2555e4949c8d8782f18ef20e9d39730d2656e218a6f1a21a4c4c0b56546a02e", + "sha256:c2695c61cf53a5d4345a43d689f37fc0f6d3a2dc520660aec27ec0f06288d1f9", + "sha256:c2b627d3c8982691b06d89d31093cee158c30629fdfebe705a91814d49b554f8", + "sha256:c46131c6112b534b178d4e002abe450a0a29840b61413ac25243f1291613806a", + "sha256:c54dc329cd44f7f7883a9f4baaefe686e8b9662e2c6c184ea15cceee587d8d69", + "sha256:c7d7cafc11d70fdd8801abfc2ff276744ae4cb39d8060b6b542c7e44e5f2cfc2", + "sha256:cb0b2d5d51f96b6cc19e6ab46a7b684be23240426ae951dcdac9639ab111b45e", + "sha256:d15a29424e96fad56dc2f3abed10a89c50c099f97d2416520c7a543e8fddf066", + "sha256:d1f5c9169e26db6a61276008582d945405b8316aae2bb198220466e68114a0f5", + "sha256:d271f770b52e32236d945911b2082f9318e90ff835d45224fa9e28374303f729", + "sha256:d646fdd74c25bbdd4a055414f0fe32896c400f38ffbdfc78c68e62812a9e0257", + "sha256:d6e395c3d1f773cf0651cd3559e25182eb0c03a2777b53b4575d8adc1149c6e9", + "sha256:d7c071235a47d407b0e93aa6262b49422dbe48d7d8566e1158fecc91043dd948", + "sha256:d97273a52d7f89a75b11ec386f786d3da7723d7efae3034b4dda79f6f093edc1", + "sha256:dcf354661f54e6a49193d0b5653a1b011ba856e0b7a76bda2c33e4c6892f34ea", + "sha256:e3e7fabedb3fe06933f47f1538df7b3a8d78e13d7167195f51ca47ee12690373", + "sha256:e525b69ee8a92c146ae5b4da9ecd15e518df4d40003b01b454ad694a27f498b5", + "sha256:e709d6ac598c5416f879bb1bae3fd751366120ac3fa235a01de763537385d036", + "sha256:e83dfefb4f7d285c2d6a07a22268344a97d61579b3e0dce482a5be0251d672ab", + "sha256:e86260b76786c28acf0b5fe31c8dca4c2add95098c709b11e8c35b424ebd4f5b", + "sha256:e883b61b75ca6efc2541fcd52a5c8ccfe288b24d97e20ac08fdf343b8ac672ea", + "sha256:f0a44bb40b6aaa4fb9a5c1ee07880570ecda2065433a96ccff409c9c20c1624a", + "sha256:f82ace0ec57c94aaf5b0e118d4366cff5889097412c75aa14b4fd5fc0c44ee3e", + "sha256:f9ca09414003c0e96a735daa1f071f7d7ed06962ef4fa29ceb6c80d06696d900", + "sha256:fa430b871220dc62572cef9c69b41e0d70fcb9d486a4a207a5de4c1f25d82593", + "sha256:fc262c3df78c8ff6020c782d9ce02e4bcffe4900ad71c0ecdad59943cba54442", + "sha256:fcd546782d03181b0b1d20b43d612429a90a68779659ba8045114b867971ab71", + "sha256:fd4ceeae2fb8cabdd1b71c82bfdd39662473d3433ec95b962200e9e752fb70d0", + "sha256:fec5fac7aea6c060f317f07494961236434928e6f4374e170ef50b3001e14581" ], "markers": "python_version >= '3.8'", - "version": "==3.9.5" + "version": "==3.10.9" }, "aiosignal": { "hashes": [ @@ -116,19 +139,19 @@ }, "attrs": { "hashes": [ - "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30", - "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1" + "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346", + "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2" ], "markers": "python_version >= '3.7'", - "version": "==23.2.0" + "version": "==24.2.0" }, "certifi": { "hashes": [ - "sha256:3cd43f1c6fa7dedc5899d69d3ad0398fd018ad1a17fba83ddaf78aa46c747516", - "sha256:ddc6c8ce995e6987e7faf5e3f1b02b302836a0e5d98ece18392cb1a36c72ad56" + "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8", + "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9" ], "markers": "python_version >= '3.6'", - "version": "==2024.6.2" + "version": "==2024.8.30" }, "charset-normalizer": { "hashes": [ @@ -311,184 +334,217 @@ }, "idna": { "hashes": [ - "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc", - "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0" + "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", + "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3" ], - "markers": "python_version >= '3.5'", - "version": "==3.7" + "markers": "python_version >= '3.6'", + "version": "==3.10" }, "multidict": { "hashes": [ - "sha256:01265f5e40f5a17f8241d52656ed27192be03bfa8764d88e8220141d1e4b3556", - "sha256:0275e35209c27a3f7951e1ce7aaf93ce0d163b28948444bec61dd7badc6d3f8c", - "sha256:04bde7a7b3de05732a4eb39c94574db1ec99abb56162d6c520ad26f83267de29", - "sha256:04da1bb8c8dbadf2a18a452639771951c662c5ad03aefe4884775454be322c9b", - "sha256:09a892e4a9fb47331da06948690ae38eaa2426de97b4ccbfafbdcbe5c8f37ff8", - "sha256:0d63c74e3d7ab26de115c49bffc92cc77ed23395303d496eae515d4204a625e7", - "sha256:107c0cdefe028703fb5dafe640a409cb146d44a6ae201e55b35a4af8e95457dd", - "sha256:141b43360bfd3bdd75f15ed811850763555a251e38b2405967f8e25fb43f7d40", - "sha256:14c2976aa9038c2629efa2c148022ed5eb4cb939e15ec7aace7ca932f48f9ba6", - "sha256:19fe01cea168585ba0f678cad6f58133db2aa14eccaf22f88e4a6dccadfad8b3", - "sha256:1d147090048129ce3c453f0292e7697d333db95e52616b3793922945804a433c", - "sha256:1d9ea7a7e779d7a3561aade7d596649fbecfa5c08a7674b11b423783217933f9", - "sha256:215ed703caf15f578dca76ee6f6b21b7603791ae090fbf1ef9d865571039ade5", - "sha256:21fd81c4ebdb4f214161be351eb5bcf385426bf023041da2fd9e60681f3cebae", - "sha256:220dd781e3f7af2c2c1053da9fa96d9cf3072ca58f057f4c5adaaa1cab8fc442", - "sha256:228b644ae063c10e7f324ab1ab6b548bdf6f8b47f3ec234fef1093bc2735e5f9", - "sha256:29bfeb0dff5cb5fdab2023a7a9947b3b4af63e9c47cae2a10ad58394b517fddc", - "sha256:2f4848aa3baa109e6ab81fe2006c77ed4d3cd1e0ac2c1fbddb7b1277c168788c", - "sha256:2faa5ae9376faba05f630d7e5e6be05be22913782b927b19d12b8145968a85ea", - "sha256:2ffc42c922dbfddb4a4c3b438eb056828719f07608af27d163191cb3e3aa6cc5", - "sha256:37b15024f864916b4951adb95d3a80c9431299080341ab9544ed148091b53f50", - "sha256:3cc2ad10255f903656017363cd59436f2111443a76f996584d1077e43ee51182", - "sha256:3d25f19500588cbc47dc19081d78131c32637c25804df8414463ec908631e453", - "sha256:403c0911cd5d5791605808b942c88a8155c2592e05332d2bf78f18697a5fa15e", - "sha256:411bf8515f3be9813d06004cac41ccf7d1cd46dfe233705933dd163b60e37600", - "sha256:425bf820055005bfc8aa9a0b99ccb52cc2f4070153e34b701acc98d201693733", - "sha256:435a0984199d81ca178b9ae2c26ec3d49692d20ee29bc4c11a2a8d4514c67eda", - "sha256:4a6a4f196f08c58c59e0b8ef8ec441d12aee4125a7d4f4fef000ccb22f8d7241", - "sha256:4cc0ef8b962ac7a5e62b9e826bd0cd5040e7d401bc45a6835910ed699037a461", - "sha256:51d035609b86722963404f711db441cf7134f1889107fb171a970c9701f92e1e", - "sha256:53689bb4e102200a4fafa9de9c7c3c212ab40a7ab2c8e474491914d2305f187e", - "sha256:55205d03e8a598cfc688c71ca8ea5f66447164efff8869517f175ea632c7cb7b", - "sha256:5c0631926c4f58e9a5ccce555ad7747d9a9f8b10619621f22f9635f069f6233e", - "sha256:5cb241881eefd96b46f89b1a056187ea8e9ba14ab88ba632e68d7a2ecb7aadf7", - "sha256:60d698e8179a42ec85172d12f50b1668254628425a6bd611aba022257cac1386", - "sha256:612d1156111ae11d14afaf3a0669ebf6c170dbb735e510a7438ffe2369a847fd", - "sha256:6214c5a5571802c33f80e6c84713b2c79e024995b9c5897f794b43e714daeec9", - "sha256:6939c95381e003f54cd4c5516740faba40cf5ad3eeff460c3ad1d3e0ea2549bf", - "sha256:69db76c09796b313331bb7048229e3bee7928eb62bab5e071e9f7fcc4879caee", - "sha256:6bf7a982604375a8d49b6cc1b781c1747f243d91b81035a9b43a2126c04766f5", - "sha256:766c8f7511df26d9f11cd3a8be623e59cca73d44643abab3f8c8c07620524e4a", - "sha256:76c0de87358b192de7ea9649beb392f107dcad9ad27276324c24c91774ca5271", - "sha256:76f067f5121dcecf0d63a67f29080b26c43c71a98b10c701b0677e4a065fbd54", - "sha256:7901c05ead4b3fb75113fb1dd33eb1253c6d3ee37ce93305acd9d38e0b5f21a4", - "sha256:79660376075cfd4b2c80f295528aa6beb2058fd289f4c9252f986751a4cd0496", - "sha256:79a6d2ba910adb2cbafc95dad936f8b9386e77c84c35bc0add315b856d7c3abb", - "sha256:7afcdd1fc07befad18ec4523a782cde4e93e0a2bf71239894b8d61ee578c1319", - "sha256:7be7047bd08accdb7487737631d25735c9a04327911de89ff1b26b81745bd4e3", - "sha256:7c6390cf87ff6234643428991b7359b5f59cc15155695deb4eda5c777d2b880f", - "sha256:7df704ca8cf4a073334e0427ae2345323613e4df18cc224f647f251e5e75a527", - "sha256:85f67aed7bb647f93e7520633d8f51d3cbc6ab96957c71272b286b2f30dc70ed", - "sha256:896ebdcf62683551312c30e20614305f53125750803b614e9e6ce74a96232604", - "sha256:92d16a3e275e38293623ebf639c471d3e03bb20b8ebb845237e0d3664914caef", - "sha256:99f60d34c048c5c2fabc766108c103612344c46e35d4ed9ae0673d33c8fb26e8", - "sha256:9fe7b0653ba3d9d65cbe7698cca585bf0f8c83dbbcc710db9c90f478e175f2d5", - "sha256:a3145cb08d8625b2d3fee1b2d596a8766352979c9bffe5d7833e0503d0f0b5e5", - "sha256:aeaf541ddbad8311a87dd695ed9642401131ea39ad7bc8cf3ef3967fd093b626", - "sha256:b55358304d7a73d7bdf5de62494aaf70bd33015831ffd98bc498b433dfe5b10c", - "sha256:b82cc8ace10ab5bd93235dfaab2021c70637005e1ac787031f4d1da63d493c1d", - "sha256:c0868d64af83169e4d4152ec612637a543f7a336e4a307b119e98042e852ad9c", - "sha256:c1c1496e73051918fcd4f58ff2e0f2f3066d1c76a0c6aeffd9b45d53243702cc", - "sha256:c9bf56195c6bbd293340ea82eafd0071cb3d450c703d2c93afb89f93b8386ccc", - "sha256:cbebcd5bcaf1eaf302617c114aa67569dd3f090dd0ce8ba9e35e9985b41ac35b", - "sha256:cd6c8fca38178e12c00418de737aef1261576bd1b6e8c6134d3e729a4e858b38", - "sha256:ceb3b7e6a0135e092de86110c5a74e46bda4bd4fbfeeb3a3bcec79c0f861e450", - "sha256:cf590b134eb70629e350691ecca88eac3e3b8b3c86992042fb82e3cb1830d5e1", - "sha256:d3eb1ceec286eba8220c26f3b0096cf189aea7057b6e7b7a2e60ed36b373b77f", - "sha256:d65f25da8e248202bd47445cec78e0025c0fe7582b23ec69c3b27a640dd7a8e3", - "sha256:d6f6d4f185481c9669b9447bf9d9cf3b95a0e9df9d169bbc17e363b7d5487755", - "sha256:d84a5c3a5f7ce6db1f999fb9438f686bc2e09d38143f2d93d8406ed2dd6b9226", - "sha256:d946b0a9eb8aaa590df1fe082cee553ceab173e6cb5b03239716338629c50c7a", - "sha256:dce1c6912ab9ff5f179eaf6efe7365c1f425ed690b03341911bf4939ef2f3046", - "sha256:de170c7b4fe6859beb8926e84f7d7d6c693dfe8e27372ce3b76f01c46e489fcf", - "sha256:e02021f87a5b6932fa6ce916ca004c4d441509d33bbdbeca70d05dff5e9d2479", - "sha256:e030047e85cbcedbfc073f71836d62dd5dadfbe7531cae27789ff66bc551bd5e", - "sha256:e0e79d91e71b9867c73323a3444724d496c037e578a0e1755ae159ba14f4f3d1", - "sha256:e4428b29611e989719874670fd152b6625500ad6c686d464e99f5aaeeaca175a", - "sha256:e4972624066095e52b569e02b5ca97dbd7a7ddd4294bf4e7247d52635630dd83", - "sha256:e7be68734bd8c9a513f2b0cfd508802d6609da068f40dc57d4e3494cefc92929", - "sha256:e8e94e6912639a02ce173341ff62cc1201232ab86b8a8fcc05572741a5dc7d93", - "sha256:ea1456df2a27c73ce51120fa2f519f1bea2f4a03a917f4a43c8707cf4cbbae1a", - "sha256:ebd8d160f91a764652d3e51ce0d2956b38efe37c9231cd82cfc0bed2e40b581c", - "sha256:eca2e9d0cc5a889850e9bbd68e98314ada174ff6ccd1129500103df7a94a7a44", - "sha256:edd08e6f2f1a390bf137080507e44ccc086353c8e98c657e666c017718561b89", - "sha256:f285e862d2f153a70586579c15c44656f888806ed0e5b56b64489afe4a2dbfba", - "sha256:f2a1dee728b52b33eebff5072817176c172050d44d67befd681609b4746e1c2e", - "sha256:f7e301075edaf50500f0b341543c41194d8df3ae5caf4702f2095f3ca73dd8da", - "sha256:fb616be3538599e797a2017cccca78e354c767165e8858ab5116813146041a24", - "sha256:fce28b3c8a81b6b36dfac9feb1de115bab619b3c13905b419ec71d03a3fc1423", - "sha256:fe5d7785250541f7f5019ab9cba2c71169dc7d74d0f45253f8313f436458a4ef" + "sha256:052e10d2d37810b99cc170b785945421141bf7bb7d2f8799d431e7db229c385f", + "sha256:06809f4f0f7ab7ea2cabf9caca7d79c22c0758b58a71f9d32943ae13c7ace056", + "sha256:071120490b47aa997cca00666923a83f02c7fbb44f71cf7f136df753f7fa8761", + "sha256:0c3f390dc53279cbc8ba976e5f8035eab997829066756d811616b652b00a23a3", + "sha256:0e2b90b43e696f25c62656389d32236e049568b39320e2735d51f08fd362761b", + "sha256:0e5f362e895bc5b9e67fe6e4ded2492d8124bdf817827f33c5b46c2fe3ffaca6", + "sha256:10524ebd769727ac77ef2278390fb0068d83f3acb7773792a5080f2b0abf7748", + "sha256:10a9b09aba0c5b48c53761b7c720aaaf7cf236d5fe394cd399c7ba662d5f9966", + "sha256:16e5f4bf4e603eb1fdd5d8180f1a25f30056f22e55ce51fb3d6ad4ab29f7d96f", + "sha256:188215fc0aafb8e03341995e7c4797860181562380f81ed0a87ff455b70bf1f1", + "sha256:189f652a87e876098bbc67b4da1049afb5f5dfbaa310dd67c594b01c10388db6", + "sha256:1ca0083e80e791cffc6efce7660ad24af66c8d4079d2a750b29001b53ff59ada", + "sha256:1e16bf3e5fc9f44632affb159d30a437bfe286ce9e02754759be5536b169b305", + "sha256:2090f6a85cafc5b2db085124d752757c9d251548cedabe9bd31afe6363e0aff2", + "sha256:20b9b5fbe0b88d0bdef2012ef7dee867f874b72528cf1d08f1d59b0e3850129d", + "sha256:22ae2ebf9b0c69d206c003e2f6a914ea33f0a932d4aa16f236afc049d9958f4a", + "sha256:22f3105d4fb15c8f57ff3959a58fcab6ce36814486500cd7485651230ad4d4ef", + "sha256:23bfd518810af7de1116313ebd9092cb9aa629beb12f6ed631ad53356ed6b86c", + "sha256:27e5fc84ccef8dfaabb09d82b7d179c7cf1a3fbc8a966f8274fcb4ab2eb4cadb", + "sha256:3380252550e372e8511d49481bd836264c009adb826b23fefcc5dd3c69692f60", + "sha256:3702ea6872c5a2a4eeefa6ffd36b042e9773f05b1f37ae3ef7264b1163c2dcf6", + "sha256:37bb93b2178e02b7b618893990941900fd25b6b9ac0fa49931a40aecdf083fe4", + "sha256:3914f5aaa0f36d5d60e8ece6a308ee1c9784cd75ec8151062614657a114c4478", + "sha256:3a37ffb35399029b45c6cc33640a92bef403c9fd388acce75cdc88f58bd19a81", + "sha256:3c8b88a2ccf5493b6c8da9076fb151ba106960a2df90c2633f342f120751a9e7", + "sha256:3e97b5e938051226dc025ec80980c285b053ffb1e25a3db2a3aa3bc046bf7f56", + "sha256:3ec660d19bbc671e3a6443325f07263be452c453ac9e512f5eb935e7d4ac28b3", + "sha256:3efe2c2cb5763f2f1b275ad2bf7a287d3f7ebbef35648a9726e3b69284a4f3d6", + "sha256:483a6aea59cb89904e1ceabd2b47368b5600fb7de78a6e4a2c2987b2d256cf30", + "sha256:4867cafcbc6585e4b678876c489b9273b13e9fff9f6d6d66add5e15d11d926cb", + "sha256:48e171e52d1c4d33888e529b999e5900356b9ae588c2f09a52dcefb158b27506", + "sha256:4a9cb68166a34117d6646c0023c7b759bf197bee5ad4272f420a0141d7eb03a0", + "sha256:4b820514bfc0b98a30e3d85462084779900347e4d49267f747ff54060cc33925", + "sha256:4e18b656c5e844539d506a0a06432274d7bd52a7487e6828c63a63d69185626c", + "sha256:4e9f48f58c2c523d5a06faea47866cd35b32655c46b443f163d08c6d0ddb17d6", + "sha256:50b3a2710631848991d0bf7de077502e8994c804bb805aeb2925a981de58ec2e", + "sha256:55b6d90641869892caa9ca42ff913f7ff1c5ece06474fbd32fb2cf6834726c95", + "sha256:57feec87371dbb3520da6192213c7d6fc892d5589a93db548331954de8248fd2", + "sha256:58130ecf8f7b8112cdb841486404f1282b9c86ccb30d3519faf301b2e5659133", + "sha256:5845c1fd4866bb5dd3125d89b90e57ed3138241540897de748cdf19de8a2fca2", + "sha256:59bfeae4b25ec05b34f1956eaa1cb38032282cd4dfabc5056d0a1ec4d696d3aa", + "sha256:5b48204e8d955c47c55b72779802b219a39acc3ee3d0116d5080c388970b76e3", + "sha256:5c09fcfdccdd0b57867577b719c69e347a436b86cd83747f179dbf0cc0d4c1f3", + "sha256:6180c0ae073bddeb5a97a38c03f30c233e0a4d39cd86166251617d1bbd0af436", + "sha256:682b987361e5fd7a139ed565e30d81fd81e9629acc7d925a205366877d8c8657", + "sha256:6b5d83030255983181005e6cfbac1617ce9746b219bc2aad52201ad121226581", + "sha256:6bb5992037f7a9eff7991ebe4273ea7f51f1c1c511e6a2ce511d0e7bdb754492", + "sha256:73eae06aa53af2ea5270cc066dcaf02cc60d2994bbb2c4ef5764949257d10f43", + "sha256:76f364861c3bfc98cbbcbd402d83454ed9e01a5224bb3a28bf70002a230f73e2", + "sha256:820c661588bd01a0aa62a1283f20d2be4281b086f80dad9e955e690c75fb54a2", + "sha256:82176036e65644a6cc5bd619f65f6f19781e8ec2e5330f51aa9ada7504cc1926", + "sha256:87701f25a2352e5bf7454caa64757642734da9f6b11384c1f9d1a8e699758057", + "sha256:9079dfc6a70abe341f521f78405b8949f96db48da98aeb43f9907f342f627cdc", + "sha256:90f8717cb649eea3504091e640a1b8568faad18bd4b9fcd692853a04475a4b80", + "sha256:957cf8e4b6e123a9eea554fa7ebc85674674b713551de587eb318a2df3e00255", + "sha256:99f826cbf970077383d7de805c0681799491cb939c25450b9b5b3ced03ca99f1", + "sha256:9f636b730f7e8cb19feb87094949ba54ee5357440b9658b2a32a5ce4bce53972", + "sha256:a114d03b938376557927ab23f1e950827c3b893ccb94b62fd95d430fd0e5cf53", + "sha256:a185f876e69897a6f3325c3f19f26a297fa058c5e456bfcff8015e9a27e83ae1", + "sha256:a7a9541cd308eed5e30318430a9c74d2132e9a8cb46b901326272d780bf2d423", + "sha256:aa466da5b15ccea564bdab9c89175c762bc12825f4659c11227f515cee76fa4a", + "sha256:aaed8b0562be4a0876ee3b6946f6869b7bcdb571a5d1496683505944e268b160", + "sha256:ab7c4ceb38d91570a650dba194e1ca87c2b543488fe9309b4212694174fd539c", + "sha256:ac10f4c2b9e770c4e393876e35a7046879d195cd123b4f116d299d442b335bcd", + "sha256:b04772ed465fa3cc947db808fa306d79b43e896beb677a56fb2347ca1a49c1fa", + "sha256:b1c416351ee6271b2f49b56ad7f308072f6f44b37118d69c2cad94f3fa8a40d5", + "sha256:b225d95519a5bf73860323e633a664b0d85ad3d5bede6d30d95b35d4dfe8805b", + "sha256:b2f59caeaf7632cc633b5cf6fc449372b83bbdf0da4ae04d5be36118e46cc0aa", + "sha256:b58c621844d55e71c1b7f7c498ce5aa6985d743a1a59034c57a905b3f153c1ef", + "sha256:bf6bea52ec97e95560af5ae576bdac3aa3aae0b6758c6efa115236d9e07dae44", + "sha256:c08be4f460903e5a9d0f76818db3250f12e9c344e79314d1d570fc69d7f4eae4", + "sha256:c7053d3b0353a8b9de430a4f4b4268ac9a4fb3481af37dfe49825bf45ca24156", + "sha256:c943a53e9186688b45b323602298ab727d8865d8c9ee0b17f8d62d14b56f0753", + "sha256:ce2186a7df133a9c895dea3331ddc5ddad42cdd0d1ea2f0a51e5d161e4762f28", + "sha256:d093be959277cb7dee84b801eb1af388b6ad3ca6a6b6bf1ed7585895789d027d", + "sha256:d094ddec350a2fb899fec68d8353c78233debde9b7d8b4beeafa70825f1c281a", + "sha256:d1a9dd711d0877a1ece3d2e4fea11a8e75741ca21954c919406b44e7cf971304", + "sha256:d569388c381b24671589335a3be6e1d45546c2988c2ebe30fdcada8457a31008", + "sha256:d618649d4e70ac6efcbba75be98b26ef5078faad23592f9b51ca492953012429", + "sha256:d83a047959d38a7ff552ff94be767b7fd79b831ad1cd9920662db05fec24fe72", + "sha256:d8fff389528cad1618fb4b26b95550327495462cd745d879a8c7c2115248e399", + "sha256:da1758c76f50c39a2efd5e9859ce7d776317eb1dd34317c8152ac9251fc574a3", + "sha256:db7457bac39421addd0c8449933ac32d8042aae84a14911a757ae6ca3eef1392", + "sha256:e27bbb6d14416713a8bd7aaa1313c0fc8d44ee48d74497a0ff4c3a1b6ccb5167", + "sha256:e617fb6b0b6953fffd762669610c1c4ffd05632c138d61ac7e14ad187870669c", + "sha256:e9aa71e15d9d9beaad2c6b9319edcdc0a49a43ef5c0a4c8265ca9ee7d6c67774", + "sha256:ec2abea24d98246b94913b76a125e855eb5c434f7c46546046372fe60f666351", + "sha256:f179dee3b863ab1c59580ff60f9d99f632f34ccb38bf67a33ec6b3ecadd0fd76", + "sha256:f4c035da3f544b1882bac24115f3e2e8760f10a0107614fc9839fd232200b875", + "sha256:f67f217af4b1ff66c68a87318012de788dd95fcfeb24cc889011f4e1c7454dfd", + "sha256:f90c822a402cb865e396a504f9fc8173ef34212a342d92e362ca498cad308e28", + "sha256:ff3827aef427c89a25cc96ded1759271a93603aba9fb977a6d264648ebf989db" ], - "markers": "python_version >= '3.7'", - "version": "==6.0.5" + "markers": "python_version >= '3.8'", + "version": "==6.1.0" }, "numpy": { "hashes": [ - "sha256:03a8c78d01d9781b28a6989f6fa1bb2c4f2d51201cf99d3dd875df6fbd96b23b", - "sha256:08beddf13648eb95f8d867350f6a018a4be2e5ad54c8d8caed89ebca558b2818", - "sha256:1af303d6b2210eb850fcf03064d364652b7120803a0b872f5211f5234b399f20", - "sha256:1dda2e7b4ec9dd512f84935c5f126c8bd8b9f2fc001e9f54af255e8c5f16b0e0", - "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010", - "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a", - "sha256:3373d5d70a5fe74a2c1bb6d2cfd9609ecf686d47a2d7b1d37a8f3b6bf6003aea", - "sha256:47711010ad8555514b434df65f7d7b076bb8261df1ca9bb78f53d3b2db02e95c", - "sha256:4c66707fabe114439db9068ee468c26bbdf909cac0fb58686a42a24de1760c71", - "sha256:50193e430acfc1346175fcbdaa28ffec49947a06918b7b92130744e81e640110", - "sha256:52b8b60467cd7dd1e9ed082188b4e6bb35aa5cdd01777621a1658910745b90be", - "sha256:60dedbb91afcbfdc9bc0b1f3f402804070deed7392c23eb7a7f07fa857868e8a", - "sha256:62b8e4b1e28009ef2846b4c7852046736bab361f7aeadeb6a5b89ebec3c7055a", - "sha256:666dbfb6ec68962c033a450943ded891bed2d54e6755e35e5835d63f4f6931d5", - "sha256:675d61ffbfa78604709862923189bad94014bef562cc35cf61d3a07bba02a7ed", - "sha256:679b0076f67ecc0138fd2ede3a8fd196dddc2ad3254069bcb9faf9a79b1cebcd", - "sha256:7349ab0fa0c429c82442a27a9673fc802ffdb7c7775fad780226cb234965e53c", - "sha256:7ab55401287bfec946ced39700c053796e7cc0e3acbef09993a9ad2adba6ca6e", - "sha256:7e50d0a0cc3189f9cb0aeb3a6a6af18c16f59f004b866cd2be1c14b36134a4a0", - "sha256:95a7476c59002f2f6c590b9b7b998306fba6a5aa646b1e22ddfeaf8f78c3a29c", - "sha256:96ff0b2ad353d8f990b63294c8986f1ec3cb19d749234014f4e7eb0112ceba5a", - "sha256:9fad7dcb1aac3c7f0584a5a8133e3a43eeb2fe127f47e3632d43d677c66c102b", - "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0", - "sha256:a354325ee03388678242a4d7ebcd08b5c727033fcff3b2f536aea978e15ee9e6", - "sha256:a4abb4f9001ad2858e7ac189089c42178fcce737e4169dc61321660f1a96c7d2", - "sha256:ab47dbe5cc8210f55aa58e4805fe224dac469cde56b9f731a4c098b91917159a", - "sha256:afedb719a9dcfc7eaf2287b839d8198e06dcd4cb5d276a3df279231138e83d30", - "sha256:b3ce300f3644fb06443ee2222c2201dd3a89ea6040541412b8fa189341847218", - "sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5", - "sha256:bfe25acf8b437eb2a8b2d49d443800a5f18508cd811fea3181723922a8a82b07", - "sha256:cd25bcecc4974d09257ffcd1f098ee778f7834c3ad767fe5db785be9a4aa9cb2", - "sha256:d209d8969599b27ad20994c8e41936ee0964e6da07478d6c35016bc386b66ad4", - "sha256:d5241e0a80d808d70546c697135da2c613f30e28251ff8307eb72ba696945764", - "sha256:edd8b5fe47dab091176d21bb6de568acdd906d1887a4584a15a9a96a1dca06ef", - "sha256:f870204a840a60da0b12273ef34f7051e98c3b5961b61b0c2c1be6dfd64fbcd3", - "sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f" + "sha256:05b2d4e667895cc55e3ff2b56077e4c8a5604361fc21a042845ea3ad67465aa8", + "sha256:12edb90831ff481f7ef5f6bc6431a9d74dc0e5ff401559a71e5e4611d4f2d466", + "sha256:13311c2db4c5f7609b462bc0f43d3c465424d25c626d95040f073e30f7570e35", + "sha256:13532a088217fa624c99b843eeb54640de23b3414b14aa66d023805eb731066c", + "sha256:13602b3174432a35b16c4cfb5de9a12d229727c3dd47a6ce35111f2ebdf66ff4", + "sha256:1600068c262af1ca9580a527d43dc9d959b0b1d8e56f8a05d830eea39b7c8af6", + "sha256:1b8cde4f11f0a975d1fd59373b32e2f5a562ade7cde4f85b7137f3de8fbb29a0", + "sha256:1c193d0b0238638e6fc5f10f1b074a6993cb13b0b431f64079a509d63d3aa8b7", + "sha256:1ebec5fd716c5a5b3d8dfcc439be82a8407b7b24b230d0ad28a81b61c2f4659a", + "sha256:242b39d00e4944431a3cd2db2f5377e15b5785920421993770cddb89992c3f3a", + "sha256:259ec80d54999cc34cd1eb8ded513cb053c3bf4829152a2e00de2371bd406f5e", + "sha256:2abbf905a0b568706391ec6fa15161fad0fb5d8b68d73c461b3c1bab6064dd62", + "sha256:2cbba4b30bf31ddbe97f1c7205ef976909a93a66bb1583e983adbd155ba72ac2", + "sha256:2ffef621c14ebb0188a8633348504a35c13680d6da93ab5cb86f4e54b7e922b5", + "sha256:30d53720b726ec36a7f88dc873f0eec8447fbc93d93a8f079dfac2629598d6ee", + "sha256:32e16a03138cabe0cb28e1007ee82264296ac0983714094380b408097a418cfe", + "sha256:43cca367bf94a14aca50b89e9bc2061683116cfe864e56740e083392f533ce7a", + "sha256:456e3b11cb79ac9946c822a56346ec80275eaf2950314b249b512896c0d2505e", + "sha256:4d6ec0d4222e8ffdab1744da2560f07856421b367928026fb540e1945f2eeeaf", + "sha256:5006b13a06e0b38d561fab5ccc37581f23c9511879be7693bd33c7cd15ca227c", + "sha256:675c741d4739af2dc20cd6c6a5c4b7355c728167845e3c6b0e824e4e5d36a6c3", + "sha256:6cdb606a7478f9ad91c6283e238544451e3a95f30fb5467fbf715964341a8a86", + "sha256:6d95f286b8244b3649b477ac066c6906fbb2905f8ac19b170e2175d3d799f4df", + "sha256:76322dcdb16fccf2ac56f99048af32259dcc488d9b7e25b51e5eca5147a3fb98", + "sha256:7c1c60328bd964b53f8b835df69ae8198659e2b9302ff9ebb7de4e5a5994db3d", + "sha256:860ec6e63e2c5c2ee5e9121808145c7bf86c96cca9ad396c0bd3e0f2798ccbe2", + "sha256:8e00ea6fc82e8a804433d3e9cedaa1051a1422cb6e443011590c14d2dea59146", + "sha256:9c6c754df29ce6a89ed23afb25550d1c2d5fdb9901d9c67a16e0b16eaf7e2550", + "sha256:a26ae94658d3ba3781d5e103ac07a876b3e9b29db53f68ed7df432fd033358a8", + "sha256:a65acfdb9c6ebb8368490dbafe83c03c7e277b37e6857f0caeadbbc56e12f4fb", + "sha256:a7d80b2e904faa63068ead63107189164ca443b42dd1930299e0d1cb041cec2e", + "sha256:a84498e0d0a1174f2b3ed769b67b656aa5460c92c9554039e11f20a05650f00d", + "sha256:ab4754d432e3ac42d33a269c8567413bdb541689b02d93788af4131018cbf366", + "sha256:ad369ed238b1959dfbade9018a740fb9392c5ac4f9b5173f420bd4f37ba1f7a0", + "sha256:b1d0fcae4f0949f215d4632be684a539859b295e2d0cb14f78ec231915d644db", + "sha256:b42a1a511c81cc78cbc4539675713bbcf9d9c3913386243ceff0e9429ca892fe", + "sha256:bd33f82e95ba7ad632bc57837ee99dba3d7e006536200c4e9124089e1bf42426", + "sha256:bdd407c40483463898b84490770199d5714dcc9dd9b792f6c6caccc523c00952", + "sha256:c6eef7a2dbd0abfb0d9eaf78b73017dbfd0b54051102ff4e6a7b2980d5ac1a03", + "sha256:c82af4b2ddd2ee72d1fc0c6695048d457e00b3582ccde72d8a1c991b808bb20f", + "sha256:d666cb72687559689e9906197e3bec7b736764df6a2e58ee265e360663e9baf7", + "sha256:d7bf0a4f9f15b32b5ba53147369e94296f5fffb783db5aacc1be15b4bf72f43b", + "sha256:d82075752f40c0ddf57e6e02673a17f6cb0f8eb3f587f63ca1eaab5594da5b17", + "sha256:da65fb46d4cbb75cb417cddf6ba5e7582eb7bb0b47db4b99c9fe5787ce5d91f5", + "sha256:e2b49c3c0804e8ecb05d59af8386ec2f74877f7ca8fd9c1e00be2672e4d399b1", + "sha256:e585c8ae871fd38ac50598f4763d73ec5497b0de9a0ab4ef5b69f01c6a046142", + "sha256:e8d3ca0a72dd8846eb6f7dfe8f19088060fcb76931ed592d29128e0219652884", + "sha256:ef444c57d664d35cac4e18c298c47d7b504c66b17c2ea91312e979fcfbdfb08a", + "sha256:f1eb068ead09f4994dec71c24b2844f1e4e4e013b9629f812f292f04bd1510d9", + "sha256:f2ded8d9b6f68cc26f8425eda5d3877b47343e68ca23d0d0846f4d312ecaa445", + "sha256:f751ed0a2f250541e19dfca9f1eafa31a392c71c832b6bb9e113b10d050cb0f1", + "sha256:faa88bc527d0f097abdc2c663cddf37c05a1c2f113716601555249805cf573f1", + "sha256:fc44e3c68ff00fd991b59092a54350e6e4911152682b4782f68070985aa9e648" ], "markers": "python_version == '3.11'", - "version": "==1.26.4" + "version": "==2.1.2" }, "pandas": { "hashes": [ - "sha256:001910ad31abc7bf06f49dcc903755d2f7f3a9186c0c040b827e522e9cef0863", - "sha256:0ca6377b8fca51815f382bd0b697a0814c8bda55115678cbc94c30aacbb6eff2", - "sha256:0cace394b6ea70c01ca1595f839cf193df35d1575986e484ad35c4aeae7266c1", - "sha256:1cb51fe389360f3b5a4d57dbd2848a5f033350336ca3b340d1c53a1fad33bcad", - "sha256:2925720037f06e89af896c70bca73459d7e6a4be96f9de79e2d440bd499fe0db", - "sha256:3e374f59e440d4ab45ca2fffde54b81ac3834cf5ae2cdfa69c90bc03bde04d76", - "sha256:40ae1dffb3967a52203105a077415a86044a2bea011b5f321c6aa64b379a3f51", - "sha256:43498c0bdb43d55cb162cdc8c06fac328ccb5d2eabe3cadeb3529ae6f0517c32", - "sha256:4abfe0be0d7221be4f12552995e58723c7422c80a659da13ca382697de830c08", - "sha256:58b84b91b0b9f4bafac2a0ac55002280c094dfc6402402332c0913a59654ab2b", - "sha256:640cef9aa381b60e296db324337a554aeeb883ead99dc8f6c18e81a93942f5f4", - "sha256:66b479b0bd07204e37583c191535505410daa8df638fd8e75ae1b383851fe921", - "sha256:696039430f7a562b74fa45f540aca068ea85fa34c244d0deee539cb6d70aa288", - "sha256:6d2123dc9ad6a814bcdea0f099885276b31b24f7edf40f6cdbc0912672e22eee", - "sha256:8635c16bf3d99040fdf3ca3db669a7250ddf49c55dc4aa8fe0ae0fa8d6dcc1f0", - "sha256:873d13d177501a28b2756375d59816c365e42ed8417b41665f346289adc68d24", - "sha256:8e5a0b00e1e56a842f922e7fae8ae4077aee4af0acb5ae3622bd4b4c30aedf99", - "sha256:8e90497254aacacbc4ea6ae5e7a8cd75629d6ad2b30025a4a8b09aa4faf55151", - "sha256:9057e6aa78a584bc93a13f0a9bf7e753a5e9770a30b4d758b8d5f2a62a9433cd", - "sha256:90c6fca2acf139569e74e8781709dccb6fe25940488755716d1d354d6bc58bce", - "sha256:92fd6b027924a7e178ac202cfbe25e53368db90d56872d20ffae94b96c7acc57", - "sha256:9dfde2a0ddef507a631dc9dc4af6a9489d5e2e740e226ad426a05cabfbd7c8ef", - "sha256:9e79019aba43cb4fda9e4d983f8e88ca0373adbb697ae9c6c43093218de28b54", - "sha256:a77e9d1c386196879aa5eb712e77461aaee433e54c68cf253053a73b7e49c33a", - "sha256:c7adfc142dac335d8c1e0dcbd37eb8617eac386596eb9e1a1b77791cf2498238", - "sha256:d187d355ecec3629624fccb01d104da7d7f391db0311145817525281e2804d23", - "sha256:ddf818e4e6c7c6f4f7c8a12709696d193976b591cc7dc50588d3d1a6b5dc8772", - "sha256:e9b79011ff7a0f4b1d6da6a61aa1aa604fb312d6647de5bad20013682d1429ce", - "sha256:eee3a87076c0756de40b05c5e9a6069c035ba43e8dd71c379e68cab2c20f16ad" + "sha256:062309c1b9ea12a50e8ce661145c6aab431b1e99530d3cd60640e255778bd43a", + "sha256:15c0e1e02e93116177d29ff83e8b1619c93ddc9c49083f237d4312337a61165d", + "sha256:1948ddde24197a0f7add2bdc4ca83bf2b1ef84a1bc8ccffd95eda17fd836ecb5", + "sha256:1db71525a1538b30142094edb9adc10be3f3e176748cd7acc2240c2f2e5aa3a4", + "sha256:22a9d949bfc9a502d320aa04e5d02feab689d61da4e7764b62c30b991c42c5f0", + "sha256:29401dbfa9ad77319367d36940cd8a0b3a11aba16063e39632d98b0e931ddf32", + "sha256:31d0ced62d4ea3e231a9f228366919a5ea0b07440d9d4dac345376fd8e1477ea", + "sha256:3508d914817e153ad359d7e069d752cdd736a247c322d932eb89e6bc84217f28", + "sha256:37e0aced3e8f539eccf2e099f65cdb9c8aa85109b0be6e93e2baff94264bdc6f", + "sha256:381175499d3802cde0eabbaf6324cce0c4f5d52ca6f8c377c29ad442f50f6348", + "sha256:38cf8125c40dae9d5acc10fa66af8ea6fdf760b2714ee482ca691fc66e6fcb18", + "sha256:3b71f27954685ee685317063bf13c7709a7ba74fc996b84fc6821c59b0f06468", + "sha256:3fc6873a41186404dad67245896a6e440baacc92f5b716ccd1bc9ed2995ab2c5", + "sha256:4850ba03528b6dd51d6c5d273c46f183f39a9baf3f0143e566b89450965b105e", + "sha256:4f18ba62b61d7e192368b84517265a99b4d7ee8912f8708660fb4a366cc82667", + "sha256:56534ce0746a58afaf7942ba4863e0ef81c9c50d3f0ae93e9497d6a41a057645", + "sha256:59ef3764d0fe818125a5097d2ae867ca3fa64df032331b7e0917cf5d7bf66b13", + "sha256:5dbca4c1acd72e8eeef4753eeca07de9b1db4f398669d5994086f788a5d7cc30", + "sha256:5de54125a92bb4d1c051c0659e6fcb75256bf799a732a87184e5ea503965bce3", + "sha256:61c5ad4043f791b61dd4752191d9f07f0ae412515d59ba8f005832a532f8736d", + "sha256:6374c452ff3ec675a8f46fd9ab25c4ad0ba590b71cf0656f8b6daa5202bca3fb", + "sha256:63cc132e40a2e084cf01adf0775b15ac515ba905d7dcca47e9a251819c575ef3", + "sha256:66108071e1b935240e74525006034333f98bcdb87ea116de573a6a0dccb6c039", + "sha256:6dfcb5ee8d4d50c06a51c2fffa6cff6272098ad6540aed1a76d15fb9318194d8", + "sha256:7c2875855b0ff77b2a64a0365e24455d9990730d6431b9e0ee18ad8acee13dbd", + "sha256:7eee9e7cea6adf3e3d24e304ac6b8300646e2a5d1cd3a3c2abed9101b0846761", + "sha256:800250ecdadb6d9c78eae4990da62743b857b470883fa27f652db8bdde7f6659", + "sha256:86976a1c5b25ae3f8ccae3a5306e443569ee3c3faf444dfd0f41cda24667ad57", + "sha256:8cd6d7cc958a3910f934ea8dbdf17b2364827bb4dafc38ce6eef6bb3d65ff09c", + "sha256:99df71520d25fade9db7c1076ac94eb994f4d2673ef2aa2e86ee039b6746d20c", + "sha256:a5a1595fe639f5988ba6a8e5bc9649af3baf26df3998a0abe56c02609392e0a4", + "sha256:ad5b65698ab28ed8d7f18790a0dc58005c7629f227be9ecc1072aa74c0c1d43a", + "sha256:b1d432e8d08679a40e2a6d8b2f9770a5c21793a6f9f47fdd52c5ce1948a5a8a9", + "sha256:b8661b0238a69d7aafe156b7fa86c44b881387509653fdf857bebc5e4008ad42", + "sha256:ba96630bc17c875161df3818780af30e43be9b166ce51c9a18c1feae342906c2", + "sha256:bc6b93f9b966093cb0fd62ff1a7e4c09e6d546ad7c1de191767baffc57628f39", + "sha256:c124333816c3a9b03fbeef3a9f230ba9a737e9e5bb4060aa2107a86cc0a497fc", + "sha256:cd8d0c3be0515c12fed0bdbae072551c8b54b7192c7b1fda0ba56059a0179698", + "sha256:d9c45366def9a3dd85a6454c0e7908f2b3b8e9c138f5dc38fed7ce720d8453ed", + "sha256:f00d1345d84d8c86a63e476bb4955e46458b304b9575dcf71102b5c705320015", + "sha256:f3a255b2c19987fbbe62a9dfd6cff7ff2aa9ccab3fc75218fd4b7530f01efa24", + "sha256:fffb8ae78d8af97f849404f21411c95062db1496aeb3e56f146f0355c9989319" ], "index": "pypi", - "version": "==2.2.2" + "markers": "python_version >= '3.9'", + "version": "==2.2.3" }, "pika": { "hashes": [ @@ -496,100 +552,216 @@ "sha256:b2a327ddddf8570b4965b3576ac77091b850262d34ce8c1d8cb4e4146aa4145f" ], "index": "pypi", + "markers": "python_version >= '3.7'", "version": "==1.3.2" }, + "propcache": { + "hashes": [ + "sha256:00181262b17e517df2cd85656fcd6b4e70946fe62cd625b9d74ac9977b64d8d9", + "sha256:0e53cb83fdd61cbd67202735e6a6687a7b491c8742dfc39c9e01e80354956763", + "sha256:1235c01ddaa80da8235741e80815ce381c5267f96cc49b1477fdcf8c047ef325", + "sha256:140fbf08ab3588b3468932974a9331aff43c0ab8a2ec2c608b6d7d1756dbb6cb", + "sha256:191db28dc6dcd29d1a3e063c3be0b40688ed76434622c53a284e5427565bbd9b", + "sha256:1e41d67757ff4fbc8ef2af99b338bfb955010444b92929e9e55a6d4dcc3c4f09", + "sha256:1ec43d76b9677637a89d6ab86e1fef70d739217fefa208c65352ecf0282be957", + "sha256:20a617c776f520c3875cf4511e0d1db847a076d720714ae35ffe0df3e440be68", + "sha256:218db2a3c297a3768c11a34812e63b3ac1c3234c3a086def9c0fee50d35add1f", + "sha256:22aa8f2272d81d9317ff5756bb108021a056805ce63dd3630e27d042c8092798", + "sha256:25a1f88b471b3bc911d18b935ecb7115dff3a192b6fef46f0bfaf71ff4f12418", + "sha256:25c8d773a62ce0451b020c7b29a35cfbc05de8b291163a7a0f3b7904f27253e6", + "sha256:2a60ad3e2553a74168d275a0ef35e8c0a965448ffbc3b300ab3a5bb9956c2162", + "sha256:2a66df3d4992bc1d725b9aa803e8c5a66c010c65c741ad901e260ece77f58d2f", + "sha256:2ccc28197af5313706511fab3a8b66dcd6da067a1331372c82ea1cb74285e036", + "sha256:2e900bad2a8456d00a113cad8c13343f3b1f327534e3589acc2219729237a2e8", + "sha256:2ee7606193fb267be4b2e3b32714f2d58cad27217638db98a60f9efb5efeccc2", + "sha256:33ac8f098df0585c0b53009f039dfd913b38c1d2edafed0cedcc0c32a05aa110", + "sha256:3444cdba6628accf384e349014084b1cacd866fbb88433cd9d279d90a54e0b23", + "sha256:363ea8cd3c5cb6679f1c2f5f1f9669587361c062e4899fce56758efa928728f8", + "sha256:375a12d7556d462dc64d70475a9ee5982465fbb3d2b364f16b86ba9135793638", + "sha256:388f3217649d6d59292b722d940d4d2e1e6a7003259eb835724092a1cca0203a", + "sha256:3947483a381259c06921612550867b37d22e1df6d6d7e8361264b6d037595f44", + "sha256:39e104da444a34830751715f45ef9fc537475ba21b7f1f5b0f4d71a3b60d7fe2", + "sha256:3c997f8c44ec9b9b0bcbf2d422cc00a1d9b9c681f56efa6ca149a941e5560da2", + "sha256:3dfafb44f7bb35c0c06eda6b2ab4bfd58f02729e7c4045e179f9a861b07c9850", + "sha256:3ebbcf2a07621f29638799828b8d8668c421bfb94c6cb04269130d8de4fb7136", + "sha256:3f88a4095e913f98988f5b338c1d4d5d07dbb0b6bad19892fd447484e483ba6b", + "sha256:439e76255daa0f8151d3cb325f6dd4a3e93043e6403e6491813bcaaaa8733887", + "sha256:4569158070180c3855e9c0791c56be3ceeb192defa2cdf6a3f39e54319e56b89", + "sha256:466c219deee4536fbc83c08d09115249db301550625c7fef1c5563a584c9bc87", + "sha256:4a9d9b4d0a9b38d1c391bb4ad24aa65f306c6f01b512e10a8a34a2dc5675d348", + "sha256:4c7dde9e533c0a49d802b4f3f218fa9ad0a1ce21f2c2eb80d5216565202acab4", + "sha256:53d1bd3f979ed529f0805dd35ddaca330f80a9a6d90bc0121d2ff398f8ed8861", + "sha256:55346705687dbd7ef0d77883ab4f6fabc48232f587925bdaf95219bae072491e", + "sha256:56295eb1e5f3aecd516d91b00cfd8bf3a13991de5a479df9e27dd569ea23959c", + "sha256:56bb5c98f058a41bb58eead194b4db8c05b088c93d94d5161728515bd52b052b", + "sha256:5a5b3bb545ead161be780ee85a2b54fdf7092815995661947812dde94a40f6fb", + "sha256:5f2564ec89058ee7c7989a7b719115bdfe2a2fb8e7a4543b8d1c0cc4cf6478c1", + "sha256:608cce1da6f2672a56b24a015b42db4ac612ee709f3d29f27a00c943d9e851de", + "sha256:63f13bf09cc3336eb04a837490b8f332e0db41da66995c9fd1ba04552e516354", + "sha256:662dd62358bdeaca0aee5761de8727cfd6861432e3bb828dc2a693aa0471a563", + "sha256:676135dcf3262c9c5081cc8f19ad55c8a64e3f7282a21266d05544450bffc3a5", + "sha256:67aeb72e0f482709991aa91345a831d0b707d16b0257e8ef88a2ad246a7280bf", + "sha256:67b69535c870670c9f9b14a75d28baa32221d06f6b6fa6f77a0a13c5a7b0a5b9", + "sha256:682a7c79a2fbf40f5dbb1eb6bfe2cd865376deeac65acf9beb607505dced9e12", + "sha256:6994984550eaf25dd7fc7bd1b700ff45c894149341725bb4edc67f0ffa94efa4", + "sha256:69d3a98eebae99a420d4b28756c8ce6ea5a29291baf2dc9ff9414b42676f61d5", + "sha256:6e2e54267980349b723cff366d1e29b138b9a60fa376664a157a342689553f71", + "sha256:73e4b40ea0eda421b115248d7e79b59214411109a5bc47d0d48e4c73e3b8fcf9", + "sha256:74acd6e291f885678631b7ebc85d2d4aec458dd849b8c841b57ef04047833bed", + "sha256:7665f04d0c7f26ff8bb534e1c65068409bf4687aa2534faf7104d7182debb336", + "sha256:7735e82e3498c27bcb2d17cb65d62c14f1100b71723b68362872bca7d0913d90", + "sha256:77a86c261679ea5f3896ec060be9dc8e365788248cc1e049632a1be682442063", + "sha256:7cf18abf9764746b9c8704774d8b06714bcb0a63641518a3a89c7f85cc02c2ad", + "sha256:83928404adf8fb3d26793665633ea79b7361efa0287dfbd372a7e74311d51ee6", + "sha256:8e40876731f99b6f3c897b66b803c9e1c07a989b366c6b5b475fafd1f7ba3fb8", + "sha256:8f188cfcc64fb1266f4684206c9de0e80f54622c3f22a910cbd200478aeae61e", + "sha256:91997d9cb4a325b60d4e3f20967f8eb08dfcb32b22554d5ef78e6fd1dda743a2", + "sha256:91ee8fc02ca52e24bcb77b234f22afc03288e1dafbb1f88fe24db308910c4ac7", + "sha256:92fe151145a990c22cbccf9ae15cae8ae9eddabfc949a219c9f667877e40853d", + "sha256:945db8ee295d3af9dbdbb698cce9bbc5c59b5c3fe328bbc4387f59a8a35f998d", + "sha256:9517d5e9e0731957468c29dbfd0f976736a0e55afaea843726e887f36fe017df", + "sha256:952e0d9d07609d9c5be361f33b0d6d650cd2bae393aabb11d9b719364521984b", + "sha256:97a58a28bcf63284e8b4d7b460cbee1edaab24634e82059c7b8c09e65284f178", + "sha256:97e48e8875e6c13909c800fa344cd54cc4b2b0db1d5f911f840458a500fde2c2", + "sha256:9e0f07b42d2a50c7dd2d8675d50f7343d998c64008f1da5fef888396b7f84630", + "sha256:a3dc1a4b165283bd865e8f8cb5f0c64c05001e0718ed06250d8cac9bec115b48", + "sha256:a3ebe9a75be7ab0b7da2464a77bb27febcb4fab46a34f9288f39d74833db7f61", + "sha256:a64e32f8bd94c105cc27f42d3b658902b5bcc947ece3c8fe7bc1b05982f60e89", + "sha256:a6ed8db0a556343d566a5c124ee483ae113acc9a557a807d439bcecc44e7dfbb", + "sha256:ad9c9b99b05f163109466638bd30ada1722abb01bbb85c739c50b6dc11f92dc3", + "sha256:b33d7a286c0dc1a15f5fc864cc48ae92a846df287ceac2dd499926c3801054a6", + "sha256:bc092ba439d91df90aea38168e11f75c655880c12782facf5cf9c00f3d42b562", + "sha256:c436130cc779806bdf5d5fae0d848713105472b8566b75ff70048c47d3961c5b", + "sha256:c5869b8fd70b81835a6f187c5fdbe67917a04d7e52b6e7cc4e5fe39d55c39d58", + "sha256:c5ecca8f9bab618340c8e848d340baf68bcd8ad90a8ecd7a4524a81c1764b3db", + "sha256:cfac69017ef97db2438efb854edf24f5a29fd09a536ff3a992b75990720cdc99", + "sha256:d2f0d0f976985f85dfb5f3d685697ef769faa6b71993b46b295cdbbd6be8cc37", + "sha256:d5bed7f9805cc29c780f3aee05de3262ee7ce1f47083cfe9f77471e9d6777e83", + "sha256:d6a21ef516d36909931a2967621eecb256018aeb11fc48656e3257e73e2e247a", + "sha256:d9b6ddac6408194e934002a69bcaadbc88c10b5f38fb9307779d1c629181815d", + "sha256:db47514ffdbd91ccdc7e6f8407aac4ee94cc871b15b577c1c324236b013ddd04", + "sha256:df81779732feb9d01e5d513fad0122efb3d53bbc75f61b2a4f29a020bc985e70", + "sha256:e4a91d44379f45f5e540971d41e4626dacd7f01004826a18cb048e7da7e96544", + "sha256:e63e3e1e0271f374ed489ff5ee73d4b6e7c60710e1f76af5f0e1a6117cd26394", + "sha256:e70fac33e8b4ac63dfc4c956fd7d85a0b1139adcfc0d964ce288b7c527537fea", + "sha256:ecddc221a077a8132cf7c747d5352a15ed763b674c0448d811f408bf803d9ad7", + "sha256:f45eec587dafd4b2d41ac189c2156461ebd0c1082d2fe7013571598abb8505d1", + "sha256:f52a68c21363c45297aca15561812d542f8fc683c85201df0bebe209e349f793", + "sha256:f571aea50ba5623c308aa146eb650eebf7dbe0fd8c5d946e28343cb3b5aad577", + "sha256:f60f0ac7005b9f5a6091009b09a419ace1610e163fa5deaba5ce3484341840e7", + "sha256:f6475a1b2ecb310c98c28d271a30df74f9dd436ee46d09236a6b750a7599ce57", + "sha256:f6d5749fdd33d90e34c2efb174c7e236829147a2713334d708746e94c4bde40d", + "sha256:f902804113e032e2cdf8c71015651c97af6418363bea8d78dc0911d56c335032", + "sha256:fa1076244f54bb76e65e22cb6910365779d5c3d71d1f18b275f1dfc7b0d71b4d", + "sha256:fc2db02409338bf36590aa985a461b2c96fce91f8e7e0f14c50c5fcc4f229016", + "sha256:ffcad6c564fe6b9b8916c1aefbb37a362deebf9394bd2974e9d84232e3e08504" + ], + "markers": "python_version >= '3.8'", + "version": "==0.2.0" + }, "pydantic": { "hashes": [ - "sha256:c46c76a40bb1296728d7a8b99aa73dd70a48c3510111ff290034f860c99c419e", - "sha256:ea91b002777bf643bb20dd717c028ec43216b24a6001a280f83877fd2655d0b4" + "sha256:d155cef71265d1e9807ed1c32b4c8deec042a44a50a4188b25ac67ecd81a9c0f", + "sha256:f048cec7b26778210e28a0459867920654d48e5e62db0958433636cde4254f12" ], "index": "pypi", - "version": "==2.7.3" + "markers": "python_version >= '3.8'", + "version": "==2.9.2" }, "pydantic-core": { "hashes": [ - "sha256:01dd777215e2aa86dfd664daed5957704b769e726626393438f9c87690ce78c3", - "sha256:0eb2a4f660fcd8e2b1c90ad566db2b98d7f3f4717c64fe0a83e0adb39766d5b8", - "sha256:0fbbdc827fe5e42e4d196c746b890b3d72876bdbf160b0eafe9f0334525119c8", - "sha256:123c3cec203e3f5ac7b000bd82235f1a3eced8665b63d18be751f115588fea30", - "sha256:14601cdb733d741b8958224030e2bfe21a4a881fb3dd6fbb21f071cabd48fa0a", - "sha256:18f469a3d2a2fdafe99296a87e8a4c37748b5080a26b806a707f25a902c040a8", - "sha256:19894b95aacfa98e7cb093cd7881a0c76f55731efad31073db4521e2b6ff5b7d", - "sha256:1b4de2e51bbcb61fdebd0ab86ef28062704f62c82bbf4addc4e37fa4b00b7cbc", - "sha256:1d886dc848e60cb7666f771e406acae54ab279b9f1e4143babc9c2258213daa2", - "sha256:1f4d26ceb5eb9eed4af91bebeae4b06c3fb28966ca3a8fb765208cf6b51102ab", - "sha256:21a5e440dbe315ab9825fcd459b8814bb92b27c974cbc23c3e8baa2b76890077", - "sha256:293afe532740370aba8c060882f7d26cfd00c94cae32fd2e212a3a6e3b7bc15e", - "sha256:2f5966897e5461f818e136b8451d0551a2e77259eb0f73a837027b47dc95dab9", - "sha256:2fd41f6eff4c20778d717af1cc50eca52f5afe7805ee530a4fbd0bae284f16e9", - "sha256:2fdf2156aa3d017fddf8aea5adfba9f777db1d6022d392b682d2a8329e087cef", - "sha256:3c40d4eaad41f78e3bbda31b89edc46a3f3dc6e171bf0ecf097ff7a0ffff7cb1", - "sha256:43d447dd2ae072a0065389092a231283f62d960030ecd27565672bd40746c507", - "sha256:44a688331d4a4e2129140a8118479443bd6f1905231138971372fcde37e43528", - "sha256:44c7486a4228413c317952e9d89598bcdfb06399735e49e0f8df643e1ccd0558", - "sha256:44cd83ab6a51da80fb5adbd9560e26018e2ac7826f9626bc06ca3dc074cd198b", - "sha256:46387e38bd641b3ee5ce247563b60c5ca098da9c56c75c157a05eaa0933ed154", - "sha256:4701b19f7e3a06ea655513f7938de6f108123bf7c86bbebb1196eb9bd35cf724", - "sha256:4748321b5078216070b151d5271ef3e7cc905ab170bbfd27d5c83ee3ec436695", - "sha256:4b06beb3b3f1479d32befd1f3079cc47b34fa2da62457cdf6c963393340b56e9", - "sha256:4d0dcc59664fcb8974b356fe0a18a672d6d7cf9f54746c05f43275fc48636851", - "sha256:4e99bc050fe65c450344421017f98298a97cefc18c53bb2f7b3531eb39bc7805", - "sha256:509daade3b8649f80d4e5ff21aa5673e4ebe58590b25fe42fac5f0f52c6f034a", - "sha256:51991a89639a912c17bef4b45c87bd83593aee0437d8102556af4885811d59f5", - "sha256:53db086f9f6ab2b4061958d9c276d1dbe3690e8dd727d6abf2321d6cce37fa94", - "sha256:564d7922e4b13a16b98772441879fcdcbe82ff50daa622d681dd682175ea918c", - "sha256:574d92eac874f7f4db0ca653514d823a0d22e2354359d0759e3f6a406db5d55d", - "sha256:578e24f761f3b425834f297b9935e1ce2e30f51400964ce4801002435a1b41ef", - "sha256:59ff3e89f4eaf14050c8022011862df275b552caef8082e37b542b066ce1ff26", - "sha256:5f09baa656c904807e832cf9cce799c6460c450c4ad80803517032da0cd062e2", - "sha256:6891a2ae0e8692679c07728819b6e2b822fb30ca7445f67bbf6509b25a96332c", - "sha256:6a750aec7bf431517a9fd78cb93c97b9b0c496090fee84a47a0d23668976b4b0", - "sha256:6f5c4d41b2771c730ea1c34e458e781b18cc668d194958e0112455fff4e402b2", - "sha256:77450e6d20016ec41f43ca4a6c63e9fdde03f0ae3fe90e7c27bdbeaece8b1ed4", - "sha256:81b5efb2f126454586d0f40c4d834010979cb80785173d1586df845a632e4e6d", - "sha256:823be1deb01793da05ecb0484d6c9e20baebb39bd42b5d72636ae9cf8350dbd2", - "sha256:834b5230b5dfc0c1ec37b2fda433b271cbbc0e507560b5d1588e2cc1148cf1ce", - "sha256:847a35c4d58721c5dc3dba599878ebbdfd96784f3fb8bb2c356e123bdcd73f34", - "sha256:86110d7e1907ab36691f80b33eb2da87d780f4739ae773e5fc83fb272f88825f", - "sha256:8951eee36c57cd128f779e641e21eb40bc5073eb28b2d23f33eb0ef14ffb3f5d", - "sha256:8a7164fe2005d03c64fd3b85649891cd4953a8de53107940bf272500ba8a788b", - "sha256:8b8bab4c97248095ae0c4455b5a1cd1cdd96e4e4769306ab19dda135ea4cdb07", - "sha256:90afc12421df2b1b4dcc975f814e21bc1754640d502a2fbcc6d41e77af5ec312", - "sha256:938cb21650855054dc54dfd9120a851c974f95450f00683399006aa6e8abb057", - "sha256:942ba11e7dfb66dc70f9ae66b33452f51ac7bb90676da39a7345e99ffb55402d", - "sha256:972658f4a72d02b8abfa2581d92d59f59897d2e9f7e708fdabe922f9087773af", - "sha256:97736815b9cc893b2b7f663628e63f436018b75f44854c8027040e05230eeddb", - "sha256:98906207f29bc2c459ff64fa007afd10a8c8ac080f7e4d5beff4c97086a3dabd", - "sha256:99457f184ad90235cfe8461c4d70ab7dd2680e28821c29eca00252ba90308c78", - "sha256:a0d829524aaefdebccb869eed855e2d04c21d2d7479b6cada7ace5448416597b", - "sha256:a2fdd81edd64342c85ac7cf2753ccae0b79bf2dfa063785503cb85a7d3593223", - "sha256:a55b5b16c839df1070bc113c1f7f94a0af4433fcfa1b41799ce7606e5c79ce0a", - "sha256:a642295cd0c8df1b86fc3dced1d067874c353a188dc8e0f744626d49e9aa51c4", - "sha256:ab86ce7c8f9bea87b9d12c7f0af71102acbf5ecbc66c17796cff45dae54ef9a5", - "sha256:abc267fa9837245cc28ea6929f19fa335f3dc330a35d2e45509b6566dc18be23", - "sha256:ae1d6df168efb88d7d522664693607b80b4080be6750c913eefb77e34c12c71a", - "sha256:b2ebef0e0b4454320274f5e83a41844c63438fdc874ea40a8b5b4ecb7693f1c4", - "sha256:b48ece5bde2e768197a2d0f6e925f9d7e3e826f0ad2271120f8144a9db18d5c8", - "sha256:b7cdf28938ac6b8b49ae5e92f2735056a7ba99c9b110a474473fd71185c1af5d", - "sha256:bb4462bd43c2460774914b8525f79b00f8f407c945d50881568f294c1d9b4443", - "sha256:bc4ff9805858bd54d1a20efff925ccd89c9d2e7cf4986144b30802bf78091c3e", - "sha256:c1322d7dd74713dcc157a2b7898a564ab091ca6c58302d5c7b4c07296e3fd00f", - "sha256:c67598100338d5d985db1b3d21f3619ef392e185e71b8d52bceacc4a7771ea7e", - "sha256:ca26a1e73c48cfc54c4a76ff78df3727b9d9f4ccc8dbee4ae3f73306a591676d", - "sha256:d323a01da91851a4f17bf592faf46149c9169d68430b3146dcba2bb5e5719abc", - "sha256:dc1803ac5c32ec324c5261c7209e8f8ce88e83254c4e1aebdc8b0a39f9ddb443", - "sha256:e00a3f196329e08e43d99b79b286d60ce46bed10f2280d25a1718399457e06be", - "sha256:e85637bc8fe81ddb73fda9e56bab24560bdddfa98aa64f87aaa4e4b6730c23d2", - "sha256:e858ac0a25074ba4bce653f9b5d0a85b7456eaddadc0ce82d3878c22489fa4ee", - "sha256:eae237477a873ab46e8dd748e515c72c0c804fb380fbe6c85533c7de51f23a8f", - "sha256:ebef0dd9bf9b812bf75bda96743f2a6c5734a02092ae7f721c048d156d5fabae", - "sha256:ec3beeada09ff865c344ff3bc2f427f5e6c26401cc6113d77e372c3fdac73864", - "sha256:f76d0ad001edd426b92233d45c746fd08f467d56100fd8f30e9ace4b005266e4", - "sha256:f85d05aa0918283cf29a30b547b4df2fbb56b45b135f9e35b6807cb28bc47951", - "sha256:f9899c94762343f2cc2fc64c13e7cae4c3cc65cdfc87dd810a31654c9b7358cc" + "sha256:0a7df63886be5e270da67e0966cf4afbae86069501d35c8c1b3b6c168f42cb36", + "sha256:0cb3da3fd1b6a5d0279a01877713dbda118a2a4fc6f0d821a57da2e464793f05", + "sha256:0dbd8dbed2085ed23b5c04afa29d8fd2771674223135dc9bc937f3c09284d071", + "sha256:0dff76e0602ca7d4cdaacc1ac4c005e0ce0dcfe095d5b5259163a80d3a10d327", + "sha256:1278e0d324f6908e872730c9102b0112477a7f7cf88b308e4fc36ce1bdb6d58c", + "sha256:128585782e5bfa515c590ccee4b727fb76925dd04a98864182b22e89a4e6ed36", + "sha256:1498bec4c05c9c787bde9125cfdcc63a41004ff167f495063191b863399b1a29", + "sha256:19442362866a753485ba5e4be408964644dd6a09123d9416c54cd49171f50744", + "sha256:1b84d168f6c48fabd1f2027a3d1bdfe62f92cade1fb273a5d68e621da0e44e6d", + "sha256:1e90d2e3bd2c3863d48525d297cd143fe541be8bbf6f579504b9712cb6b643ec", + "sha256:20152074317d9bed6b7a95ade3b7d6054845d70584216160860425f4fbd5ee9e", + "sha256:216f9b2d7713eb98cb83c80b9c794de1f6b7e3145eef40400c62e86cee5f4e1e", + "sha256:233710f069d251feb12a56da21e14cca67994eab08362207785cf8c598e74577", + "sha256:255a8ef062cbf6674450e668482456abac99a5583bbafb73f9ad469540a3a232", + "sha256:2584f7cf844ac4d970fba483a717dbe10c1c1c96a969bf65d61ffe94df1b2863", + "sha256:2971bb5ffe72cc0f555c13e19b23c85b654dd2a8f7ab493c262071377bfce9f6", + "sha256:29d2c342c4bc01b88402d60189f3df065fb0dda3654744d5a165a5288a657368", + "sha256:2e203fdf807ac7e12ab59ca2bfcabb38c7cf0b33c41efeb00f8e5da1d86af480", + "sha256:33e3d65a85a2a4a0dc3b092b938a4062b1a05f3a9abde65ea93b233bca0e03f2", + "sha256:374a5e5049eda9e0a44c696c7ade3ff355f06b1fe0bb945ea3cac2bc336478a2", + "sha256:37b0fe330e4a58d3c58b24d91d1eb102aeec675a3db4c292ec3928ecd892a9a6", + "sha256:3d5639516376dce1940ea36edf408c554475369f5da2abd45d44621cb616f769", + "sha256:42c6dcb030aefb668a2b7009c85b27f90e51e6a3b4d5c9bc4c57631292015b0d", + "sha256:4a7cd62e831afe623fbb7aabbb4fe583212115b3ef38a9f6b71869ba644624a2", + "sha256:4ba762ed58e8d68657fc1281e9bb72e1c3e79cc5d464be146e260c541ec12d84", + "sha256:4fc714bdbfb534f94034efaa6eadd74e5b93c8fa6315565a222f7b6f42ca1166", + "sha256:4ffa2ebd4c8530079140dd2d7f794a9d9a73cbb8e9d59ffe24c63436efa8f271", + "sha256:5a1504ad17ba4210df3a045132a7baeeba5a200e930f57512ee02909fc5c4cb5", + "sha256:5c364564d17da23db1106787675fc7af45f2f7b58b4173bfdd105564e132e6fb", + "sha256:5e11661ce0fd30a6790e8bcdf263b9ec5988e95e63cf901972107efc49218b13", + "sha256:5f54b118ce5de9ac21c363d9b3caa6c800341e8c47a508787e5868c6b79c9323", + "sha256:5f5ff8d839f4566a474a969508fe1c5e59c31c80d9e140566f9a37bba7b8d556", + "sha256:61817945f2fe7d166e75fbfb28004034b48e44878177fc54d81688e7b85a3665", + "sha256:624e278a7d29b6445e4e813af92af37820fafb6dcc55c012c834f9e26f9aaaef", + "sha256:63e46b3169866bd62849936de036f901a9356e36376079b05efa83caeaa02ceb", + "sha256:6531b7ca5f951d663c339002e91aaebda765ec7d61b7d1e3991051906ddde119", + "sha256:68665f4c17edcceecc112dfed5dbe6f92261fb9d6054b47d01bf6371a6196126", + "sha256:696dd8d674d6ce621ab9d45b205df149399e4bb9aa34102c970b721554828510", + "sha256:6f783e0ec4803c787bcea93e13e9932edab72068f68ecffdf86a99fd5918878b", + "sha256:723314c1d51722ab28bfcd5240d858512ffd3116449c557a1336cbe3919beb87", + "sha256:74b9127ffea03643e998e0c5ad9bd3811d3dac8c676e47db17b0ee7c3c3bf35f", + "sha256:7530e201d10d7d14abce4fb54cfe5b94a0aefc87da539d0346a484ead376c3cc", + "sha256:77733e3892bb0a7fa797826361ce8a9184d25c8dffaec60b7ffe928153680ba8", + "sha256:78ddaaa81421a29574a682b3179d4cf9e6d405a09b99d93ddcf7e5239c742e21", + "sha256:7c9129eb40958b3d4500fa2467e6a83356b3b61bfff1b414c7361d9220f9ae8f", + "sha256:7d32706badfe136888bdea71c0def994644e09fff0bfe47441deaed8e96fdbc6", + "sha256:81965a16b675b35e1d09dd14df53f190f9129c0202356ed44ab2728b1c905658", + "sha256:8394d940e5d400d04cad4f75c0598665cbb81aecefaca82ca85bd28264af7f9b", + "sha256:86d2f57d3e1379a9525c5ab067b27dbb8a0642fb5d454e17a9ac434f9ce523e3", + "sha256:883a91b5dd7d26492ff2f04f40fbb652de40fcc0afe07e8129e8ae779c2110eb", + "sha256:88ad334a15b32a791ea935af224b9de1bf99bcd62fabf745d5f3442199d86d59", + "sha256:9261d3ce84fa1d38ed649c3638feefeae23d32ba9182963e465d58d62203bd24", + "sha256:97df63000f4fea395b2824da80e169731088656d1818a11b95f3b173747b6cd9", + "sha256:98d134c954828488b153d88ba1f34e14259284f256180ce659e8d83e9c05eaa3", + "sha256:996a38a83508c54c78a5f41456b0103c30508fed9abcad0a59b876d7398f25fd", + "sha256:9a5bce9d23aac8f0cf0836ecfc033896aa8443b501c58d0602dbfd5bd5b37753", + "sha256:9a6b5099eeec78827553827f4c6b8615978bb4b6a88e5d9b93eddf8bb6790f55", + "sha256:9d18368b137c6295db49ce7218b1a9ba15c5bc254c96d7c9f9e924a9bc7825ad", + "sha256:a4fa4fc04dff799089689f4fd502ce7d59de529fc2f40a2c8836886c03e0175a", + "sha256:a5c7ba8ffb6d6f8f2ab08743be203654bb1aaa8c9dcb09f82ddd34eadb695605", + "sha256:aea443fffa9fbe3af1a9ba721a87f926fe548d32cab71d188a6ede77d0ff244e", + "sha256:b10bd51f823d891193d4717448fab065733958bdb6a6b351967bd349d48d5c9b", + "sha256:ba1a0996f6c2773bd83e63f18914c1de3c9dd26d55f4ac302a7efe93fb8e7433", + "sha256:bb2802e667b7051a1bebbfe93684841cc9351004e2badbd6411bf357ab8d5ac8", + "sha256:cfdd16ab5e59fc31b5e906d1a3f666571abc367598e3e02c83403acabc092e07", + "sha256:d06b0c8da4f16d1d1e352134427cb194a0a6e19ad5db9161bf32b2113409e728", + "sha256:d0776dea117cf5272382634bd2a5c1b6eb16767c223c6a5317cd3e2a757c61a0", + "sha256:d18ca8148bebe1b0a382a27a8ee60350091a6ddaf475fa05ef50dc35b5df6327", + "sha256:d4488a93b071c04dc20f5cecc3631fc78b9789dd72483ba15d423b5b3689b555", + "sha256:d5f7a395a8cf1621939692dba2a6b6a830efa6b3cee787d82c7de1ad2930de64", + "sha256:d7a80d21d613eec45e3d41eb22f8f94ddc758a6c4720842dc74c0581f54993d6", + "sha256:d97683ddee4723ae8c95d1eddac7c192e8c552da0c73a925a89fa8649bf13eea", + "sha256:dcedcd19a557e182628afa1d553c3895a9f825b936415d0dbd3cd0bbcfd29b4b", + "sha256:de6d1d1b9e5101508cb37ab0d972357cac5235f5c6533d1071964c47139257df", + "sha256:df49e7a0861a8c36d089c1ed57d308623d60416dab2647a4a17fe050ba85de0e", + "sha256:df933278128ea1cd77772673c73954e53a1c95a4fdf41eef97c2b779271bd0bd", + "sha256:e08277a400de01bc72436a0ccd02bdf596631411f592ad985dcee21445bd0068", + "sha256:e38e63e6f3d1cec5a27e0afe90a085af8b6806ee208b33030e65b6516353f1a3", + "sha256:e55541f756f9b3ee346b840103f32779c695a19826a4c442b7954550a0972040", + "sha256:ec4e55f79b1c4ffb2eecd8a0cfba9955a2588497d96851f4c8f99aa4a1d39b12", + "sha256:ed1a53de42fbe34853ba90513cea21673481cd81ed1be739f7f2efb931b24916", + "sha256:ed541d70698978a20eb63d8c5d72f2cc6d7079d9d90f6b50bad07826f1320f5f", + "sha256:f09e2ff1f17c2b51f2bc76d1cc33da96298f0a036a137f5440ab3ec5360b624f", + "sha256:f220b0eea5965dec25480b6333c788fb72ce5f9129e8759ef876a1d805d00801", + "sha256:f3e0da4ebaef65158d4dfd7d3678aad692f7666877df0002b8a522cdf088f231", + "sha256:f455ee30a9d61d3e1a15abd5068827773d6e4dc513e795f380cdd59932c782d5", + "sha256:f5ef8f42bec47f21d07668a043f077d507e5bf4e668d5c6dfe6aaba89de1a5b8", + "sha256:f69a8e0b033b747bb3e36a44e7732f0c99f7edd5cea723d45bc0d6e95377ffee", + "sha256:ff02b6d461a6de369f07ec15e465a88895f3223eb75073ffea56b84d9331f607" ], "markers": "python_version >= '3.8'", - "version": "==2.18.4" + "version": "==2.23.4" }, "python-dateutil": { "hashes": [ @@ -601,10 +773,10 @@ }, "pytz": { "hashes": [ - "sha256:2a29735ea9c18baf14b448846bde5a48030ed267578472d8955cd0e7443a9812", - "sha256:328171f4e3623139da4983451950b28e95ac706e13f3f2630a879749e7a8b319" + "sha256:2aa355083c50a0f93fa581709deac0c9ad65cca8a9e9beac660adcbd493c798a", + "sha256:31c7c1817eb7fae7ca4b8c7ee50c72f93aa2dd863de768e1ef4245d426aa0725" ], - "version": "==2024.1" + "version": "==2024.2" }, "requests": { "hashes": [ @@ -612,6 +784,7 @@ "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6" ], "index": "pypi", + "markers": "python_version >= '3.8'", "version": "==2.32.3" }, "six": { @@ -624,11 +797,11 @@ }, "tinydb": { "hashes": [ - "sha256:30c06d12383d7c332e404ca6a6103fb2b32cbf25712689648c39d9a6bd34bd3d", - "sha256:6dd686a9c5a75dfa9280088fd79a419aefe19cd7f4bd85eba203540ef856d564" + "sha256:09c4c6a239da9be676b948f1f28074cffd1cf08e7af920c1df50424cc8bee8d6", + "sha256:1c7c507ef520c789f94f1f5786f0722a98a59a85031a2e81e2accc701721f07f" ], - "markers": "python_version >= '3.7' and python_version < '4.0'", - "version": "==4.8.0" + "markers": "python_version >= '3.8' and python_version < '4.0'", + "version": "==4.8.1" }, "tuspy": { "hashes": [ @@ -636,145 +809,148 @@ "sha256:024d3d1745120098a85635e42242039ca6b1bc787f561ec974fffb45fc775c1b" ], "index": "pypi", + "markers": "python_full_version >= '3.5.3'", "version": "==1.0.3" }, "typing-extensions": { "hashes": [ - "sha256:6024b58b69089e5a89c347397254e35f1bf02a907728ec7fee9bf0fe837d203a", - "sha256:915f5e35ff76f56588223f15fdd5938f9a1cf9195c0de25130c627e4d597f6d1" + "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", + "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8" ], - "markers": "python_version >= '3.8'", - "version": "==4.12.1" + "markers": "python_version < '3.13'", + "version": "==4.12.2" }, "tzdata": { "hashes": [ - "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd", - "sha256:9068bc196136463f5245e51efda838afa15aaeca9903f49050dfa2679db4d252" + "sha256:7d85cc416e9382e69095b7bdf4afd9e3880418a2413feec7069d533d6b4e31cc", + "sha256:a48093786cdcde33cad18c2555e8532f34422074448fbc874186f0abd79565cd" ], "markers": "python_version >= '2'", - "version": "==2024.1" + "version": "==2024.2" }, "urllib3": { "hashes": [ - "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d", - "sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19" + "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac", + "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9" ], "markers": "python_version >= '3.8'", - "version": "==2.2.1" + "version": "==2.2.3" }, "yarl": { "hashes": [ - "sha256:008d3e808d03ef28542372d01057fd09168419cdc8f848efe2804f894ae03e51", - "sha256:03caa9507d3d3c83bca08650678e25364e1843b484f19986a527630ca376ecce", - "sha256:07574b007ee20e5c375a8fe4a0789fad26db905f9813be0f9fef5a68080de559", - "sha256:09efe4615ada057ba2d30df871d2f668af661e971dfeedf0c159927d48bbeff0", - "sha256:0d2454f0aef65ea81037759be5ca9947539667eecebca092733b2eb43c965a81", - "sha256:0e9d124c191d5b881060a9e5060627694c3bdd1fe24c5eecc8d5d7d0eb6faabc", - "sha256:18580f672e44ce1238b82f7fb87d727c4a131f3a9d33a5e0e82b793362bf18b4", - "sha256:1f23e4fe1e8794f74b6027d7cf19dc25f8b63af1483d91d595d4a07eca1fb26c", - "sha256:206a55215e6d05dbc6c98ce598a59e6fbd0c493e2de4ea6cc2f4934d5a18d130", - "sha256:23d32a2594cb5d565d358a92e151315d1b2268bc10f4610d098f96b147370136", - "sha256:26a1dc6285e03f3cc9e839a2da83bcbf31dcb0d004c72d0730e755b33466c30e", - "sha256:29e0f83f37610f173eb7e7b5562dd71467993495e568e708d99e9d1944f561ec", - "sha256:2b134fd795e2322b7684155b7855cc99409d10b2e408056db2b93b51a52accc7", - "sha256:2d47552b6e52c3319fede1b60b3de120fe83bde9b7bddad11a69fb0af7db32f1", - "sha256:357495293086c5b6d34ca9616a43d329317feab7917518bc97a08f9e55648455", - "sha256:35a2b9396879ce32754bd457d31a51ff0a9d426fd9e0e3c33394bf4b9036b099", - "sha256:3777ce5536d17989c91696db1d459574e9a9bd37660ea7ee4d3344579bb6f129", - "sha256:3986b6f41ad22988e53d5778f91855dc0399b043fc8946d4f2e68af22ee9ff10", - "sha256:44d8ffbb9c06e5a7f529f38f53eda23e50d1ed33c6c869e01481d3fafa6b8142", - "sha256:49a180c2e0743d5d6e0b4d1a9e5f633c62eca3f8a86ba5dd3c471060e352ca98", - "sha256:4aa9741085f635934f3a2583e16fcf62ba835719a8b2b28fb2917bb0537c1dfa", - "sha256:4b21516d181cd77ebd06ce160ef8cc2a5e9ad35fb1c5930882baff5ac865eee7", - "sha256:4b3c1ffe10069f655ea2d731808e76e0f452fc6c749bea04781daf18e6039525", - "sha256:4c7d56b293cc071e82532f70adcbd8b61909eec973ae9d2d1f9b233f3d943f2c", - "sha256:4e9035df8d0880b2f1c7f5031f33f69e071dfe72ee9310cfc76f7b605958ceb9", - "sha256:54525ae423d7b7a8ee81ba189f131054defdb122cde31ff17477951464c1691c", - "sha256:549d19c84c55d11687ddbd47eeb348a89df9cb30e1993f1b128f4685cd0ebbf8", - "sha256:54beabb809ffcacbd9d28ac57b0db46e42a6e341a030293fb3185c409e626b8b", - "sha256:566db86717cf8080b99b58b083b773a908ae40f06681e87e589a976faf8246bf", - "sha256:5a2e2433eb9344a163aced6a5f6c9222c0786e5a9e9cac2c89f0b28433f56e23", - "sha256:5aef935237d60a51a62b86249839b51345f47564208c6ee615ed2a40878dccdd", - "sha256:604f31d97fa493083ea21bd9b92c419012531c4e17ea6da0f65cacdcf5d0bd27", - "sha256:63b20738b5aac74e239622d2fe30df4fca4942a86e31bf47a81a0e94c14df94f", - "sha256:686a0c2f85f83463272ddffd4deb5e591c98aac1897d65e92319f729c320eece", - "sha256:6a962e04b8f91f8c4e5917e518d17958e3bdee71fd1d8b88cdce74dd0ebbf434", - "sha256:6ad6d10ed9b67a382b45f29ea028f92d25bc0bc1daf6c5b801b90b5aa70fb9ec", - "sha256:6f5cb257bc2ec58f437da2b37a8cd48f666db96d47b8a3115c29f316313654ff", - "sha256:6fe79f998a4052d79e1c30eeb7d6c1c1056ad33300f682465e1b4e9b5a188b78", - "sha256:7855426dfbddac81896b6e533ebefc0af2f132d4a47340cee6d22cac7190022d", - "sha256:7d5aaac37d19b2904bb9dfe12cdb08c8443e7ba7d2852894ad448d4b8f442863", - "sha256:801e9264d19643548651b9db361ce3287176671fb0117f96b5ac0ee1c3530d53", - "sha256:81eb57278deb6098a5b62e88ad8281b2ba09f2f1147c4767522353eaa6260b31", - "sha256:824d6c50492add5da9374875ce72db7a0733b29c2394890aef23d533106e2b15", - "sha256:8397a3817d7dcdd14bb266283cd1d6fc7264a48c186b986f32e86d86d35fbac5", - "sha256:848cd2a1df56ddbffeb375535fb62c9d1645dde33ca4d51341378b3f5954429b", - "sha256:84fc30f71689d7fc9168b92788abc977dc8cefa806909565fc2951d02f6b7d57", - "sha256:8619d6915b3b0b34420cf9b2bb6d81ef59d984cb0fde7544e9ece32b4b3043c3", - "sha256:8a854227cf581330ffa2c4824d96e52ee621dd571078a252c25e3a3b3d94a1b1", - "sha256:8be9e837ea9113676e5754b43b940b50cce76d9ed7d2461df1af39a8ee674d9f", - "sha256:928cecb0ef9d5a7946eb6ff58417ad2fe9375762382f1bf5c55e61645f2c43ad", - "sha256:957b4774373cf6f709359e5c8c4a0af9f6d7875db657adb0feaf8d6cb3c3964c", - "sha256:992f18e0ea248ee03b5a6e8b3b4738850ae7dbb172cc41c966462801cbf62cf7", - "sha256:9fc5fc1eeb029757349ad26bbc5880557389a03fa6ada41703db5e068881e5f2", - "sha256:a00862fb23195b6b8322f7d781b0dc1d82cb3bcac346d1e38689370cc1cc398b", - "sha256:a3a6ed1d525bfb91b3fc9b690c5a21bb52de28c018530ad85093cc488bee2dd2", - "sha256:a6327976c7c2f4ee6816eff196e25385ccc02cb81427952414a64811037bbc8b", - "sha256:a7409f968456111140c1c95301cadf071bd30a81cbd7ab829169fb9e3d72eae9", - "sha256:a825ec844298c791fd28ed14ed1bffc56a98d15b8c58a20e0e08c1f5f2bea1be", - "sha256:a8c1df72eb746f4136fe9a2e72b0c9dc1da1cbd23b5372f94b5820ff8ae30e0e", - "sha256:a9bd00dc3bc395a662900f33f74feb3e757429e545d831eef5bb280252631984", - "sha256:aa102d6d280a5455ad6a0f9e6d769989638718e938a6a0a2ff3f4a7ff8c62cc4", - "sha256:aaaea1e536f98754a6e5c56091baa1b6ce2f2700cc4a00b0d49eca8dea471074", - "sha256:ad4d7a90a92e528aadf4965d685c17dacff3df282db1121136c382dc0b6014d2", - "sha256:b8477c1ee4bd47c57d49621a062121c3023609f7a13b8a46953eb6c9716ca392", - "sha256:ba6f52cbc7809cd8d74604cce9c14868306ae4aa0282016b641c661f981a6e91", - "sha256:bac8d525a8dbc2a1507ec731d2867025d11ceadcb4dd421423a5d42c56818541", - "sha256:bef596fdaa8f26e3d66af846bbe77057237cb6e8efff8cd7cc8dff9a62278bbf", - "sha256:c0ec0ed476f77db9fb29bca17f0a8fcc7bc97ad4c6c1d8959c507decb22e8572", - "sha256:c38c9ddb6103ceae4e4498f9c08fac9b590c5c71b0370f98714768e22ac6fa66", - "sha256:c7224cab95645c7ab53791022ae77a4509472613e839dab722a72abe5a684575", - "sha256:c74018551e31269d56fab81a728f683667e7c28c04e807ba08f8c9e3bba32f14", - "sha256:ca06675212f94e7a610e85ca36948bb8fc023e458dd6c63ef71abfd482481aa5", - "sha256:d1d2532b340b692880261c15aee4dc94dd22ca5d61b9db9a8a361953d36410b1", - "sha256:d25039a474c4c72a5ad4b52495056f843a7ff07b632c1b92ea9043a3d9950f6e", - "sha256:d5ff2c858f5f6a42c2a8e751100f237c5e869cbde669a724f2062d4c4ef93551", - "sha256:d7d7f7de27b8944f1fee2c26a88b4dabc2409d2fea7a9ed3df79b67277644e17", - "sha256:d7eeb6d22331e2fd42fce928a81c697c9ee2d51400bd1a28803965883e13cead", - "sha256:d8a1c6c0be645c745a081c192e747c5de06e944a0d21245f4cf7c05e457c36e0", - "sha256:d8b889777de69897406c9fb0b76cdf2fd0f31267861ae7501d93003d55f54fbe", - "sha256:d9e09c9d74f4566e905a0b8fa668c58109f7624db96a2171f21747abc7524234", - "sha256:db8e58b9d79200c76956cefd14d5c90af54416ff5353c5bfd7cbe58818e26ef0", - "sha256:ddb2a5c08a4eaaba605340fdee8fc08e406c56617566d9643ad8bf6852778fc7", - "sha256:e0381b4ce23ff92f8170080c97678040fc5b08da85e9e292292aba67fdac6c34", - "sha256:e23a6d84d9d1738dbc6e38167776107e63307dfc8ad108e580548d1f2c587f42", - "sha256:e516dc8baf7b380e6c1c26792610230f37147bb754d6426462ab115a02944385", - "sha256:ea65804b5dc88dacd4a40279af0cdadcfe74b3e5b4c897aa0d81cf86927fee78", - "sha256:ec61d826d80fc293ed46c9dd26995921e3a82146feacd952ef0757236fc137be", - "sha256:ee04010f26d5102399bd17f8df8bc38dc7ccd7701dc77f4a68c5b8d733406958", - "sha256:f3bc6af6e2b8f92eced34ef6a96ffb248e863af20ef4fde9448cc8c9b858b749", - "sha256:f7d6b36dd2e029b6bcb8a13cf19664c7b8e19ab3a58e0fefbb5b8461447ed5ec" + "sha256:047b258e00b99091b6f90355521f026238c63bd76dcf996d93527bb13320eefd", + "sha256:06ff23462398333c78b6f4f8d3d70410d657a471c2c5bbe6086133be43fc8f1a", + "sha256:07f9eaf57719d6721ab15805d85f4b01a5b509a0868d7320134371bcb652152d", + "sha256:0aa92e3e30a04f9462a25077db689c4ac5ea9ab6cc68a2e563881b987d42f16d", + "sha256:0cf21f46a15d445417de8fc89f2568852cf57fe8ca1ab3d19ddb24d45c0383ae", + "sha256:0fd7b941dd1b00b5f0acb97455fea2c4b7aac2dd31ea43fb9d155e9bc7b78664", + "sha256:147e36331f6f63e08a14640acf12369e041e0751bb70d9362df68c2d9dcf0c87", + "sha256:16a682a127930f3fc4e42583becca6049e1d7214bcad23520c590edd741d2114", + "sha256:176110bff341b6730f64a1eb3a7070e12b373cf1c910a9337e7c3240497db76f", + "sha256:19268b4fec1d7760134f2de46ef2608c2920134fb1fa61e451f679e41356dc55", + "sha256:1b16f6c75cffc2dc0616ea295abb0e1967601bd1fb1e0af6a1de1c6c887f3439", + "sha256:1bfc25aa6a7c99cf86564210f79a0b7d4484159c67e01232b116e445b3036547", + "sha256:1ca3894e9e9f72da93544f64988d9c052254a338a9f855165f37f51edb6591de", + "sha256:1dda53508df0de87b6e6b0a52d6718ff6c62a5aca8f5552748404963df639269", + "sha256:217a782020b875538eebf3948fac3a7f9bbbd0fd9bf8538f7c2ad7489e80f4e8", + "sha256:2192f718db4a8509f63dd6d950f143279211fa7e6a2c612edc17d85bf043d36e", + "sha256:29a84a46ec3ebae7a1c024c055612b11e9363a8a23238b3e905552d77a2bc51b", + "sha256:3007a5b75cb50140708420fe688c393e71139324df599434633019314ceb8b59", + "sha256:30600ba5db60f7c0820ef38a2568bb7379e1418ecc947a0f76fd8b2ff4257a97", + "sha256:337912bcdcf193ade64b9aae5a4017a0a1950caf8ca140362e361543c6773f21", + "sha256:37001e5d4621cef710c8dc1429ca04e189e572f128ab12312eab4e04cf007132", + "sha256:3d569f877ed9a708e4c71a2d13d2940cb0791da309f70bd970ac1a5c088a0a92", + "sha256:4009def9be3a7e5175db20aa2d7307ecd00bbf50f7f0f989300710eee1d0b0b9", + "sha256:46a9772a1efa93f9cd170ad33101c1817c77e0e9914d4fe33e2da299d7cf0f9b", + "sha256:47eede5d11d669ab3759b63afb70d28d5328c14744b8edba3323e27dc52d298d", + "sha256:498b3c55087b9d762636bca9b45f60d37e51d24341786dc01b81253f9552a607", + "sha256:4e0d45ebf975634468682c8bec021618b3ad52c37619e5c938f8f831fa1ac5c0", + "sha256:4f24f08b6c9b9818fd80612c97857d28f9779f0d1211653ece9844fc7b414df2", + "sha256:55c144d363ad4626ca744556c049c94e2b95096041ac87098bb363dcc8635e8d", + "sha256:582cedde49603f139be572252a318b30dc41039bc0b8165f070f279e5d12187f", + "sha256:587c3cc59bc148a9b1c07a019346eda2549bc9f468acd2f9824d185749acf0a6", + "sha256:5cd5dad8366e0168e0fd23d10705a603790484a6dbb9eb272b33673b8f2cce72", + "sha256:5d02d700705d67e09e1f57681f758f0b9d4412eeb70b2eb8d96ca6200b486db3", + "sha256:625f207b1799e95e7c823f42f473c1e9dbfb6192bd56bba8695656d92be4535f", + "sha256:659603d26d40dd4463200df9bfbc339fbfaed3fe32e5c432fe1dc2b5d4aa94b4", + "sha256:689a99a42ee4583fcb0d3a67a0204664aa1539684aed72bdafcbd505197a91c4", + "sha256:68ac1a09392ed6e3fd14be880d39b951d7b981fd135416db7d18a6208c536561", + "sha256:6a615cad11ec3428020fb3c5a88d85ce1b5c69fd66e9fcb91a7daa5e855325dd", + "sha256:73bedd2be05f48af19f0f2e9e1353921ce0c83f4a1c9e8556ecdcf1f1eae4892", + "sha256:742aef0a99844faaac200564ea6f5e08facb285d37ea18bd1a5acf2771f3255a", + "sha256:75ff4c819757f9bdb35de049a509814d6ce851fe26f06eb95a392a5640052482", + "sha256:781e2495e408a81e4eaeedeb41ba32b63b1980dddf8b60dbbeff6036bcd35049", + "sha256:7a9f917966d27f7ce30039fe8d900f913c5304134096554fd9bea0774bcda6d1", + "sha256:7e2637d75e92763d1322cb5041573279ec43a80c0f7fbbd2d64f5aee98447b17", + "sha256:8089d4634d8fa2b1806ce44fefa4979b1ab2c12c0bc7ef3dfa45c8a374811348", + "sha256:816d24f584edefcc5ca63428f0b38fee00b39fe64e3c5e558f895a18983efe96", + "sha256:8385ab36bf812e9d37cf7613999a87715f27ef67a53f0687d28c44b819df7cb0", + "sha256:85cb3e40eaa98489f1e2e8b29f5ad02ee1ee40d6ce6b88d50cf0f205de1d9d2c", + "sha256:8648180b34faaea4aa5b5ca7e871d9eb1277033fa439693855cf0ea9195f85f1", + "sha256:8892fa575ac9b1b25fae7b221bc4792a273877b9b56a99ee2d8d03eeb3dbb1d2", + "sha256:88c7d9d58aab0724b979ab5617330acb1c7030b79379c8138c1c8c94e121d1b3", + "sha256:8a2f8fb7f944bcdfecd4e8d855f84c703804a594da5123dd206f75036e536d4d", + "sha256:8f4e475f29a9122f908d0f1f706e1f2fc3656536ffd21014ff8a6f2e1b14d1d8", + "sha256:8f50eb3837012a937a2b649ec872b66ba9541ad9d6f103ddcafb8231cfcafd22", + "sha256:91d875f75fabf76b3018c5f196bf3d308ed2b49ddcb46c1576d6b075754a1393", + "sha256:94b2bb9bcfd5be9d27004ea4398fb640373dd0c1a9e219084f42c08f77a720ab", + "sha256:9557c9322aaa33174d285b0c1961fb32499d65ad1866155b7845edc876c3c835", + "sha256:95e16e9eaa2d7f5d87421b8fe694dd71606aa61d74b824c8d17fc85cc51983d1", + "sha256:96952f642ac69075e44c7d0284528938fdff39422a1d90d3e45ce40b72e5e2d9", + "sha256:985623575e5c4ea763056ffe0e2d63836f771a8c294b3de06d09480538316b13", + "sha256:99ff3744f5fe48288be6bc402533b38e89749623a43208e1d57091fc96b783b9", + "sha256:9abe80ae2c9d37c17599557b712e6515f4100a80efb2cda15f5f070306477cd2", + "sha256:a152751af7ef7b5d5fa6d215756e508dd05eb07d0cf2ba51f3e740076aa74373", + "sha256:a2e4725a08cb2b4794db09e350c86dee18202bb8286527210e13a1514dc9a59a", + "sha256:a56fbe3d7f3bce1d060ea18d2413a2ca9ca814eea7cedc4d247b5f338d54844e", + "sha256:ab3abc0b78a5dfaa4795a6afbe7b282b6aa88d81cf8c1bb5e394993d7cae3457", + "sha256:b03384eed107dbeb5f625a99dc3a7de8be04fc8480c9ad42fccbc73434170b20", + "sha256:b0547ab1e9345dc468cac8368d88ea4c5bd473ebc1d8d755347d7401982b5dd8", + "sha256:b4c1ecba93e7826dc71ddba75fb7740cdb52e7bd0be9f03136b83f54e6a1f511", + "sha256:b693c63e7e64b524f54aa4888403c680342d1ad0d97be1707c531584d6aeeb4f", + "sha256:b6d0147574ce2e7b812c989e50fa72bbc5338045411a836bd066ce5fc8ac0bce", + "sha256:b9cfef3f14f75bf6aba73a76caf61f9d00865912a04a4393c468a7ce0981b519", + "sha256:b9f805e37ed16cc212fdc538a608422d7517e7faf539bedea4fe69425bc55d76", + "sha256:bab03192091681d54e8225c53f270b0517637915d9297028409a2a5114ff4634", + "sha256:bc24f968b82455f336b79bf37dbb243b7d76cd40897489888d663d4e028f5069", + "sha256:c14b504a74e58e2deb0378b3eca10f3d076635c100f45b113c18c770b4a47a50", + "sha256:c2089a9afef887664115f7fa6d3c0edd6454adaca5488dba836ca91f60401075", + "sha256:c8ed4034f0765f8861620c1f2f2364d2e58520ea288497084dae880424fc0d9f", + "sha256:cd2660c01367eb3ef081b8fa0a5da7fe767f9427aa82023a961a5f28f0d4af6c", + "sha256:d8361c7d04e6a264481f0b802e395f647cd3f8bbe27acfa7c12049efea675bd1", + "sha256:d9baec588f015d0ee564057aa7574313c53a530662ffad930b7886becc85abdf", + "sha256:dbd9ff43a04f8ffe8a959a944c2dca10d22f5f99fc6a459f49c3ebfb409309d9", + "sha256:e3f8bfc1db82589ef965ed234b87de30d140db8b6dc50ada9e33951ccd8ec07a", + "sha256:e6a2c5c5bb2556dfbfffffc2bcfb9c235fd2b566d5006dfb2a37afc7e3278a07", + "sha256:e749af6c912a7bb441d105c50c1a3da720474e8acb91c89350080dd600228f0e", + "sha256:e85d86527baebb41a214cc3b45c17177177d900a2ad5783dbe6f291642d4906f", + "sha256:ee2c68e4f2dd1b1c15b849ba1c96fac105fca6ffdb7c1e8be51da6fabbdeafb9", + "sha256:f3ab950f8814f3b7b5e3eebc117986f817ec933676f68f0a6c5b2137dd7c9c69", + "sha256:f4f4547944d4f5cfcdc03f3f097d6f05bbbc915eaaf80a2ee120d0e756de377d", + "sha256:f72a0d746d38cb299b79ce3d4d60ba0892c84bbc905d0d49c13df5bace1b65f8", + "sha256:fc2c80bc87fba076e6cbb926216c27fba274dae7100a7b9a0983b53132dd99f2", + "sha256:fe4d2536c827f508348d7b40c08767e8c7071614250927233bf0c92170451c0a" ], - "markers": "python_version >= '3.7'", - "version": "==1.9.4" + "markers": "python_version >= '3.8'", + "version": "==1.14.0" } }, "develop": { "alabaster": { "hashes": [ - "sha256:75a8b99c28a5dad50dd7f8ccdd447a121ddb3892da9e53d1ca5cca3106d58d65", - "sha256:b46733c07dce03ae4e150330b975c75737fa60f0a7c591b6c8bf4928a28e2c92" + "sha256:c00dca57bca26fa62a6d7d0a9fcce65f3e026e9bfe33e9c538fd3fbb2144fd9e", + "sha256:fc6786402dc3fcb2de3cabd5fe455a2db534b371124f1f21de8731783dec828b" ], - "markers": "python_version >= '3.9'", - "version": "==0.7.16" + "markers": "python_version >= '3.10'", + "version": "==1.0.0" }, "babel": { "hashes": [ - "sha256:08706bdad8d0a3413266ab61bd6c34d0c28d6e1e7badf40a2cebe67644e2e1fb", - "sha256:8daf0e265d05768bc6c7a314cf1321e9a123afc328cc635c18622a2f30a04413" + "sha256:368b5b98b37c06b7daf6696391c3240c938b37767d4584413e8438c5c435fa8b", + "sha256:d1f3554ca26605fe173f3de0c65f750f5a42f924499bf134de6423582298e316" ], "markers": "python_version >= '3.8'", - "version": "==2.15.0" + "version": "==2.16.0" }, "backports.tarfile": { "hashes": [ @@ -794,77 +970,93 @@ }, "build": { "hashes": [ - "sha256:526263f4870c26f26c433545579475377b2b7588b6f1eac76a001e873ae3e19d", - "sha256:75e10f767a433d9a86e50d83f418e83efc18ede923ee5ff7df93b6cb0306c5d4" + "sha256:1d61c0887fa860c01971625baae8bdd338e517b836a2f70dd1f7aa3a6b2fc5b5", + "sha256:b36993e92ca9375a219c99e606a122ff365a760a2d4bba0caa09bd5278b608b7" ], "index": "pypi", - "version": "==1.2.1" + "markers": "python_version >= '3.8'", + "version": "==1.2.2.post1" }, "certifi": { "hashes": [ - "sha256:3cd43f1c6fa7dedc5899d69d3ad0398fd018ad1a17fba83ddaf78aa46c747516", - "sha256:ddc6c8ce995e6987e7faf5e3f1b02b302836a0e5d98ece18392cb1a36c72ad56" + "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8", + "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9" ], "markers": "python_version >= '3.6'", - "version": "==2024.6.2" + "version": "==2024.8.30" }, "cffi": { "hashes": [ - "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc", - "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a", - "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417", - "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab", - "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520", - "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36", - "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743", - "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8", - "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed", - "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684", - "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56", - "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324", - "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d", - "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235", - "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e", - "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088", - "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000", - "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7", - "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e", - "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673", - "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c", - "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe", - "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2", - "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098", - "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8", - "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a", - "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0", - "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b", - "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896", - "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e", - "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9", - "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2", - "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b", - "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6", - "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404", - "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f", - "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0", - "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4", - "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc", - "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936", - "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba", - "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872", - "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb", - "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614", - "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1", - "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d", - "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969", - "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b", - "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4", - "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627", - "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956", - "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357" + "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8", + "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2", + "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1", + "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15", + "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36", + "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", + "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8", + "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36", + "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17", + "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf", + "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc", + "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3", + "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed", + "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702", + "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1", + "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8", + "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903", + "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6", + "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d", + "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b", + "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e", + "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be", + "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c", + "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683", + "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9", + "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c", + "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8", + "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1", + "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4", + "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655", + "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67", + "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595", + "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0", + "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65", + "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41", + "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6", + "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401", + "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6", + "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3", + "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16", + "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93", + "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e", + "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4", + "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964", + "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c", + "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576", + "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0", + "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3", + "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662", + "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3", + "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff", + "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5", + "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd", + "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f", + "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5", + "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14", + "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d", + "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9", + "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7", + "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382", + "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a", + "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e", + "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a", + "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4", + "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99", + "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87", + "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b" ], "markers": "platform_python_implementation != 'PyPy'", - "version": "==1.16.0" + "version": "==1.17.1" }, "charset-normalizer": { "hashes": [ @@ -964,99 +1156,115 @@ }, "coverage": { "hashes": [ - "sha256:015eddc5ccd5364dcb902eaecf9515636806fa1e0d5bef5769d06d0f31b54523", - "sha256:04aefca5190d1dc7a53a4c1a5a7f8568811306d7a8ee231c42fb69215571944f", - "sha256:05ac5f60faa0c704c0f7e6a5cbfd6f02101ed05e0aee4d2822637a9e672c998d", - "sha256:0bbddc54bbacfc09b3edaec644d4ac90c08ee8ed4844b0f86227dcda2d428fcb", - "sha256:1d2a830ade66d3563bb61d1e3c77c8def97b30ed91e166c67d0632c018f380f0", - "sha256:239a4e75e09c2b12ea478d28815acf83334d32e722e7433471fbf641c606344c", - "sha256:244f509f126dc71369393ce5fea17c0592c40ee44e607b6d855e9c4ac57aac98", - "sha256:25a5caf742c6195e08002d3b6c2dd6947e50efc5fc2c2205f61ecb47592d2d83", - "sha256:296a7d9bbc598e8744c00f7a6cecf1da9b30ae9ad51c566291ff1314e6cbbed8", - "sha256:2e079c9ec772fedbade9d7ebc36202a1d9ef7291bc9b3a024ca395c4d52853d7", - "sha256:33ca90a0eb29225f195e30684ba4a6db05dbef03c2ccd50b9077714c48153cac", - "sha256:33fc65740267222fc02975c061eb7167185fef4cc8f2770267ee8bf7d6a42f84", - "sha256:341dd8f61c26337c37988345ca5c8ccabeff33093a26953a1ac72e7d0103c4fb", - "sha256:34d6d21d8795a97b14d503dcaf74226ae51eb1f2bd41015d3ef332a24d0a17b3", - "sha256:3538d8fb1ee9bdd2e2692b3b18c22bb1c19ffbefd06880f5ac496e42d7bb3884", - "sha256:38a3b98dae8a7c9057bd91fbf3415c05e700a5114c5f1b5b0ea5f8f429ba6614", - "sha256:3d5a67f0da401e105753d474369ab034c7bae51a4c31c77d94030d59e41df5bd", - "sha256:50084d3516aa263791198913a17354bd1dc627d3c1639209640b9cac3fef5807", - "sha256:55f689f846661e3f26efa535071775d0483388a1ccfab899df72924805e9e7cd", - "sha256:5bc5a8c87714b0c67cfeb4c7caa82b2d71e8864d1a46aa990b5588fa953673b8", - "sha256:62bda40da1e68898186f274f832ef3e759ce929da9a9fd9fcf265956de269dbc", - "sha256:705f3d7c2b098c40f5b81790a5fedb274113373d4d1a69e65f8b68b0cc26f6db", - "sha256:75e3f4e86804023e991096b29e147e635f5e2568f77883a1e6eed74512659ab0", - "sha256:7b2a19e13dfb5c8e145c7a6ea959485ee8e2204699903c88c7d25283584bfc08", - "sha256:7cec2af81f9e7569280822be68bd57e51b86d42e59ea30d10ebdbb22d2cb7232", - "sha256:8383a6c8cefba1b7cecc0149415046b6fc38836295bc4c84e820872eb5478b3d", - "sha256:8c836309931839cca658a78a888dab9676b5c988d0dd34ca247f5f3e679f4e7a", - "sha256:8e317953bb4c074c06c798a11dbdd2cf9979dbcaa8ccc0fa4701d80042d4ebf1", - "sha256:923b7b1c717bd0f0f92d862d1ff51d9b2b55dbbd133e05680204465f454bb286", - "sha256:990fb20b32990b2ce2c5f974c3e738c9358b2735bc05075d50a6f36721b8f303", - "sha256:9aad68c3f2566dfae84bf46295a79e79d904e1c21ccfc66de88cd446f8686341", - "sha256:a5812840d1d00eafae6585aba38021f90a705a25b8216ec7f66aebe5b619fb84", - "sha256:a6519d917abb15e12380406d721e37613e2a67d166f9fb7e5a8ce0375744cd45", - "sha256:ab0b028165eea880af12f66086694768f2c3139b2c31ad5e032c8edbafca6ffc", - "sha256:aea7da970f1feccf48be7335f8b2ca64baf9b589d79e05b9397a06696ce1a1ec", - "sha256:b1196e13c45e327d6cd0b6e471530a1882f1017eb83c6229fc613cd1a11b53cd", - "sha256:b368e1aee1b9b75757942d44d7598dcd22a9dbb126affcbba82d15917f0cc155", - "sha256:bde997cac85fcac227b27d4fb2c7608a2c5f6558469b0eb704c5726ae49e1c52", - "sha256:c4c2872b3c91f9baa836147ca33650dc5c172e9273c808c3c3199c75490e709d", - "sha256:c59d2ad092dc0551d9f79d9d44d005c945ba95832a6798f98f9216ede3d5f485", - "sha256:d1da0a2e3b37b745a2b2a678a4c796462cf753aebf94edcc87dcc6b8641eae31", - "sha256:d8b7339180d00de83e930358223c617cc343dd08e1aa5ec7b06c3a121aec4e1d", - "sha256:dd4b3355b01273a56b20c219e74e7549e14370b31a4ffe42706a8cda91f19f6d", - "sha256:e08c470c2eb01977d221fd87495b44867a56d4d594f43739a8028f8646a51e0d", - "sha256:f5102a92855d518b0996eb197772f5ac2a527c0ec617124ad5242a3af5e25f85", - "sha256:f542287b1489c7a860d43a7d8883e27ca62ab84ca53c965d11dac1d3a1fab7ce", - "sha256:f78300789a708ac1f17e134593f577407d52d0417305435b134805c4fb135adb", - "sha256:f81bc26d609bf0fbc622c7122ba6307993c83c795d2d6f6f6fd8c000a770d974", - "sha256:f836c174c3a7f639bded48ec913f348c4761cbf49de4a20a956d3431a7c9cb24", - "sha256:fa21a04112c59ad54f69d80e376f7f9d0f5f9123ab87ecd18fbb9ec3a2beed56", - "sha256:fcf7d1d6f5da887ca04302db8e0e0cf56ce9a5e05f202720e49b3e8157ddb9a9", - "sha256:fd27d8b49e574e50caa65196d908f80e4dff64d7e592d0c59788b45aad7e8b35" + "sha256:06a737c882bd26d0d6ee7269b20b12f14a8704807a01056c80bb881a4b2ce6ca", + "sha256:07e2ca0ad381b91350c0ed49d52699b625aab2b44b65e1b4e02fa9df0e92ad2d", + "sha256:0c0420b573964c760df9e9e86d1a9a622d0d27f417e1a949a8a66dd7bcee7bc6", + "sha256:0dbde0f4aa9a16fa4d754356a8f2e36296ff4d83994b2c9d8398aa32f222f989", + "sha256:1125ca0e5fd475cbbba3bb67ae20bd2c23a98fac4e32412883f9bcbaa81c314c", + "sha256:13b0a73a0896988f053e4fbb7de6d93388e6dd292b0d87ee51d106f2c11b465b", + "sha256:166811d20dfea725e2e4baa71fffd6c968a958577848d2131f39b60043400223", + "sha256:170d444ab405852903b7d04ea9ae9b98f98ab6d7e63e1115e82620807519797f", + "sha256:1f4aa8219db826ce6be7099d559f8ec311549bfc4046f7f9fe9b5cea5c581c56", + "sha256:225667980479a17db1048cb2bf8bfb39b8e5be8f164b8f6628b64f78a72cf9d3", + "sha256:260933720fdcd75340e7dbe9060655aff3af1f0c5d20f46b57f262ab6c86a5e8", + "sha256:2bdb062ea438f22d99cba0d7829c2ef0af1d768d1e4a4f528087224c90b132cb", + "sha256:2c09f4ce52cb99dd7505cd0fc8e0e37c77b87f46bc9c1eb03fe3bc9991085388", + "sha256:3115a95daa9bdba70aea750db7b96b37259a81a709223c8448fa97727d546fe0", + "sha256:3e0cadcf6733c09154b461f1ca72d5416635e5e4ec4e536192180d34ec160f8a", + "sha256:3f1156e3e8f2872197af3840d8ad307a9dd18e615dc64d9ee41696f287c57ad8", + "sha256:4421712dbfc5562150f7554f13dde997a2e932a6b5f352edcce948a815efee6f", + "sha256:44df346d5215a8c0e360307d46ffaabe0f5d3502c8a1cefd700b34baf31d411a", + "sha256:502753043567491d3ff6d08629270127e0c31d4184c4c8d98f92c26f65019962", + "sha256:547f45fa1a93154bd82050a7f3cddbc1a7a4dd2a9bf5cb7d06f4ae29fe94eaf8", + "sha256:5621a9175cf9d0b0c84c2ef2b12e9f5f5071357c4d2ea6ca1cf01814f45d2391", + "sha256:609b06f178fe8e9f89ef676532760ec0b4deea15e9969bf754b37f7c40326dbc", + "sha256:645786266c8f18a931b65bfcefdbf6952dd0dea98feee39bd188607a9d307ed2", + "sha256:6878ef48d4227aace338d88c48738a4258213cd7b74fd9a3d4d7582bb1d8a155", + "sha256:6a89ecca80709d4076b95f89f308544ec8f7b4727e8a547913a35f16717856cb", + "sha256:6db04803b6c7291985a761004e9060b2bca08da6d04f26a7f2294b8623a0c1a0", + "sha256:6e2cd258d7d927d09493c8df1ce9174ad01b381d4729a9d8d4e38670ca24774c", + "sha256:6e81d7a3e58882450ec4186ca59a3f20a5d4440f25b1cff6f0902ad890e6748a", + "sha256:702855feff378050ae4f741045e19a32d57d19f3e0676d589df0575008ea5004", + "sha256:78b260de9790fd81e69401c2dc8b17da47c8038176a79092a89cb2b7d945d060", + "sha256:7bb65125fcbef8d989fa1dd0e8a060999497629ca5b0efbca209588a73356232", + "sha256:7dea0889685db8550f839fa202744652e87c60015029ce3f60e006f8c4462c93", + "sha256:8284cf8c0dd272a247bc154eb6c95548722dce90d098c17a883ed36e67cdb129", + "sha256:877abb17e6339d96bf08e7a622d05095e72b71f8afd8a9fefc82cf30ed944163", + "sha256:8929543a7192c13d177b770008bc4e8119f2e1f881d563fc6b6305d2d0ebe9de", + "sha256:8ae539519c4c040c5ffd0632784e21b2f03fc1340752af711f33e5be83a9d6c6", + "sha256:8f59d57baca39b32db42b83b2a7ba6f47ad9c394ec2076b084c3f029b7afca23", + "sha256:9054a0754de38d9dbd01a46621636689124d666bad1936d76c0341f7d71bf569", + "sha256:953510dfb7b12ab69d20135a0662397f077c59b1e6379a768e97c59d852ee51d", + "sha256:95cae0efeb032af8458fc27d191f85d1717b1d4e49f7cb226cf526ff28179778", + "sha256:9bc572be474cafb617672c43fe989d6e48d3c83af02ce8de73fff1c6bb3c198d", + "sha256:9c56863d44bd1c4fe2abb8a4d6f5371d197f1ac0ebdee542f07f35895fc07f36", + "sha256:9e0b2df163b8ed01d515807af24f63de04bebcecbd6c3bfeff88385789fdf75a", + "sha256:a09ece4a69cf399510c8ab25e0950d9cf2b42f7b3cb0374f95d2e2ff594478a6", + "sha256:a1ac0ae2b8bd743b88ed0502544847c3053d7171a3cff9228af618a068ed9c34", + "sha256:a318d68e92e80af8b00fa99609796fdbcdfef3629c77c6283566c6f02c6d6704", + "sha256:a4acd025ecc06185ba2b801f2de85546e0b8ac787cf9d3b06e7e2a69f925b106", + "sha256:a6d3adcf24b624a7b778533480e32434a39ad8fa30c315208f6d3e5542aeb6e9", + "sha256:a78d169acd38300060b28d600344a803628c3fd585c912cacc9ea8790fe96862", + "sha256:a95324a9de9650a729239daea117df21f4b9868ce32e63f8b650ebe6cef5595b", + "sha256:abd5fd0db5f4dc9289408aaf34908072f805ff7792632250dcb36dc591d24255", + "sha256:b06079abebbc0e89e6163b8e8f0e16270124c154dc6e4a47b413dd538859af16", + "sha256:b43c03669dc4618ec25270b06ecd3ee4fa94c7f9b3c14bae6571ca00ef98b0d3", + "sha256:b48f312cca9621272ae49008c7f613337c53fadca647d6384cc129d2996d1133", + "sha256:b5d7b556859dd85f3a541db6a4e0167b86e7273e1cdc973e5b175166bb634fdb", + "sha256:b9f222de8cded79c49bf184bdbc06630d4c58eec9459b939b4a690c82ed05657", + "sha256:c3c02d12f837d9683e5ab2f3d9844dc57655b92c74e286c262e0fc54213c216d", + "sha256:c44fee9975f04b33331cb8eb272827111efc8930cfd582e0320613263ca849ca", + "sha256:cf4b19715bccd7ee27b6b120e7e9dd56037b9c0681dcc1adc9ba9db3d417fa36", + "sha256:d0c212c49b6c10e6951362f7c6df3329f04c2b1c28499563d4035d964ab8e08c", + "sha256:d3296782ca4eab572a1a4eca686d8bfb00226300dcefdf43faa25b5242ab8a3e", + "sha256:d85f5e9a5f8b73e2350097c3756ef7e785f55bd71205defa0bfdaf96c31616ff", + "sha256:da511e6ad4f7323ee5702e6633085fb76c2f893aaf8ce4c51a0ba4fc07580ea7", + "sha256:e05882b70b87a18d937ca6768ff33cc3f72847cbc4de4491c8e73880766718e5", + "sha256:e61c0abb4c85b095a784ef23fdd4aede7a2628478e7baba7c5e3deba61070a02", + "sha256:e6a08c0be454c3b3beb105c0596ebdc2371fab6bb90c0c0297f4e58fd7e1012c", + "sha256:e9a6e0eb86070e8ccaedfbd9d38fec54864f3125ab95419970575b42af7541df", + "sha256:ed37bd3c3b063412f7620464a9ac1314d33100329f39799255fb8d3027da50d3", + "sha256:f1adfc8ac319e1a348af294106bc6a8458a0f1633cc62a1446aebc30c5fa186a", + "sha256:f5796e664fe802da4f57a168c85359a8fbf3eab5e55cd4e4569fbacecc903959", + "sha256:fc5a77d0c516700ebad189b587de289a20a78324bc54baee03dd486f0855d234", + "sha256:fd21f6ae3f08b41004dfb433fa895d858f3f5979e7762d052b12aef444e29afc" ], "index": "pypi", - "version": "==7.5.3" + "markers": "python_version >= '3.8'", + "version": "==7.6.1" }, "cryptography": { "hashes": [ - "sha256:013629ae70b40af70c9a7a5db40abe5d9054e6f4380e50ce769947b73bf3caad", - "sha256:2346b911eb349ab547076f47f2e035fc8ff2c02380a7cbbf8d87114fa0f1c583", - "sha256:2f66d9cd9147ee495a8374a45ca445819f8929a3efcd2e3df6428e46c3cbb10b", - "sha256:2f88d197e66c65be5e42cd72e5c18afbfae3f741742070e3019ac8f4ac57262c", - "sha256:31f721658a29331f895a5a54e7e82075554ccfb8b163a18719d342f5ffe5ecb1", - "sha256:343728aac38decfdeecf55ecab3264b015be68fc2816ca800db649607aeee648", - "sha256:5226d5d21ab681f432a9c1cf8b658c0cb02533eece706b155e5fbd8a0cdd3949", - "sha256:57080dee41209e556a9a4ce60d229244f7a66ef52750f813bfbe18959770cfba", - "sha256:5a94eccb2a81a309806027e1670a358b99b8fe8bfe9f8d329f27d72c094dde8c", - "sha256:6b7c4f03ce01afd3b76cf69a5455caa9cfa3de8c8f493e0d3ab7d20611c8dae9", - "sha256:7016f837e15b0a1c119d27ecd89b3515f01f90a8615ed5e9427e30d9cdbfed3d", - "sha256:81884c4d096c272f00aeb1f11cf62ccd39763581645b0812e99a91505fa48e0c", - "sha256:81d8a521705787afe7a18d5bfb47ea9d9cc068206270aad0b96a725022e18d2e", - "sha256:8d09d05439ce7baa8e9e95b07ec5b6c886f548deb7e0f69ef25f64b3bce842f2", - "sha256:961e61cefdcb06e0c6d7e3a1b22ebe8b996eb2bf50614e89384be54c48c6b63d", - "sha256:9c0c1716c8447ee7dbf08d6db2e5c41c688544c61074b54fc4564196f55c25a7", - "sha256:a0608251135d0e03111152e41f0cc2392d1e74e35703960d4190b2e0f4ca9c70", - "sha256:a0c5b2b0585b6af82d7e385f55a8bc568abff8923af147ee3c07bd8b42cda8b2", - "sha256:ad803773e9df0b92e0a817d22fd8a3675493f690b96130a5e24f1b8fabbea9c7", - "sha256:b297f90c5723d04bcc8265fc2a0f86d4ea2e0f7ab4b6994459548d3a6b992a14", - "sha256:ba4f0a211697362e89ad822e667d8d340b4d8d55fae72cdd619389fb5912eefe", - "sha256:c4783183f7cb757b73b2ae9aed6599b96338eb957233c58ca8f49a49cc32fd5e", - "sha256:c9bb2ae11bfbab395bdd072985abde58ea9860ed84e59dbc0463a5d0159f5b71", - "sha256:cafb92b2bc622cd1aa6a1dce4b93307792633f4c5fe1f46c6b97cf67073ec961", - "sha256:d45b940883a03e19e944456a558b67a41160e367a719833c53de6911cabba2b7", - "sha256:dc0fdf6787f37b1c6b08e6dfc892d9d068b5bdb671198c72072828b80bd5fe4c", - "sha256:dea567d1b0e8bc5764b9443858b673b734100c2871dc93163f58c46a97a83d28", - "sha256:dec9b018df185f08483f294cae6ccac29e7a6e0678996587363dc352dc65c842", - "sha256:e3ec3672626e1b9e55afd0df6d774ff0e953452886e06e0f1eb7eb0c832e8902", - "sha256:e599b53fd95357d92304510fb7bda8523ed1f79ca98dce2f43c115950aa78801", - "sha256:fa76fbb7596cc5839320000cdd5d0955313696d9511debab7ee7278fc8b5c84a", - "sha256:fff12c88a672ab9c9c1cf7b0c80e3ad9e2ebd9d828d955c126be4fd3e5578c9e" + "sha256:014f58110f53237ace6a408b5beb6c427b64e084eb451ef25a28308270086494", + "sha256:1bbcce1a551e262dfbafb6e6252f1ae36a248e615ca44ba302df077a846a8806", + "sha256:203e92a75716d8cfb491dc47c79e17d0d9207ccffcbcb35f598fbe463ae3444d", + "sha256:27e613d7077ac613e399270253259d9d53872aaf657471473ebfc9a52935c062", + "sha256:2bd51274dcd59f09dd952afb696bf9c61a7a49dfc764c04dd33ef7a6b502a1e2", + "sha256:38926c50cff6f533f8a2dae3d7f19541432610d114a70808f0926d5aaa7121e4", + "sha256:511f4273808ab590912a93ddb4e3914dfd8a388fed883361b02dea3791f292e1", + "sha256:58d4e9129985185a06d849aa6df265bdd5a74ca6e1b736a77959b498e0505b85", + "sha256:5b43d1ea6b378b54a1dc99dd8a2b5be47658fe9a7ce0a58ff0b55f4b43ef2b84", + "sha256:61ec41068b7b74268fa86e3e9e12b9f0c21fcf65434571dbb13d954bceb08042", + "sha256:666ae11966643886c2987b3b721899d250855718d6d9ce41b521252a17985f4d", + "sha256:68aaecc4178e90719e95298515979814bda0cbada1256a4485414860bd7ab962", + "sha256:7c05650fe8023c5ed0d46793d4b7d7e6cd9c04e68eabe5b0aeea836e37bdcec2", + "sha256:80eda8b3e173f0f247f711eef62be51b599b5d425c429b5d4ca6a05e9e856baa", + "sha256:8385d98f6a3bf8bb2d65a73e17ed87a3ba84f6991c155691c51112075f9ffc5d", + "sha256:88cce104c36870d70c49c7c8fd22885875d950d9ee6ab54df2745f83ba0dc365", + "sha256:9d3cdb25fa98afdd3d0892d132b8d7139e2c087da1712041f6b762e4f807cc96", + "sha256:a575913fb06e05e6b4b814d7f7468c2c660e8bb16d8d5a1faf9b33ccc569dd47", + "sha256:ac119bb76b9faa00f48128b7f5679e1d8d437365c5d26f1c2c3f0da4ce1b553d", + "sha256:c1332724be35d23a854994ff0b66530119500b6053d0bd3363265f7e5e77288d", + "sha256:d03a475165f3134f773d1388aeb19c2d25ba88b6a9733c5c590b9ff7bbfa2e0c", + "sha256:d75601ad10b059ec832e78823b348bfa1a59f6b8d545db3a24fd44362a1564cb", + "sha256:de41fd81a41e53267cb020bb3a7212861da53a7d39f863585d13ea11049cf277", + "sha256:e710bf40870f4db63c3d7d929aa9e09e4e7ee219e703f949ec4073b4294f6172", + "sha256:ea25acb556320250756e53f9e20a4177515f012c9eaea17eb7587a8c4d8ae034", + "sha256:f98bf604c82c416bc829e490c700ca1553eafdf2912a91e23a79d97d9801372a", + "sha256:fba1007b3ef89946dbbb515aeeb41e30203b004f0b4b00e5e16078b518563289" ], "markers": "python_version >= '3.7'", - "version": "==42.0.8" + "version": "==43.0.1" }, "docutils": { "hashes": [ @@ -1068,19 +1276,20 @@ }, "furo": { "hashes": [ - "sha256:490a00d08c0a37ecc90de03ae9227e8eb5d6f7f750edf9807f398a2bdf2358de", - "sha256:81f205a6605ebccbb883350432b4831c0196dd3d1bc92f61e1f459045b3d2b0b" + "sha256:6cd97c58b47813d3619e63e9081169880fbe331f0ca883c871ff1f3f11814f5c", + "sha256:b63e4cee8abfc3136d3bc03a3d45a76a850bada4d6374d24c1716b0e01394a01" ], "index": "pypi", - "version": "==2024.5.6" + "markers": "python_version >= '3.8'", + "version": "==2024.8.6" }, "idna": { "hashes": [ - "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc", - "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0" + "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", + "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3" ], - "markers": "python_version >= '3.5'", - "version": "==3.7" + "markers": "python_version >= '3.6'", + "version": "==3.10" }, "imagesize": { "hashes": [ @@ -1092,11 +1301,11 @@ }, "importlib-metadata": { "hashes": [ - "sha256:30962b96c0c223483ed6cc7280e7f0199feb01a0e40cfae4d4450fc6fab1f570", - "sha256:b78938b926ee8d5f020fc4772d487045805a55ddbad2ecf21c6d60938dc7fcd2" + "sha256:45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b", + "sha256:71522656f0abace1d072b9e5481a48f07c138e00f079c38c8f883823f9c26bd7" ], "markers": "python_version >= '3.8'", - "version": "==7.1.0" + "version": "==8.5.0" }, "iniconfig": { "hashes": [ @@ -1116,19 +1325,19 @@ }, "jaraco.context": { "hashes": [ - "sha256:3e16388f7da43d384a1a7cd3452e72e14732ac9fe459678773a3608a812bf266", - "sha256:c2f67165ce1f9be20f32f650f25d8edfc1646a8aeee48ae06fb35f90763576d2" + "sha256:9bae4ea555cf0b14938dc0aee7c9f32ed303aa20a3b73e7dc80111628792d1b3", + "sha256:f797fc481b490edb305122c9181830a3a5b76d84ef6d1aef2fb9b47ab956f9e4" ], "markers": "python_version >= '3.8'", - "version": "==5.3.0" + "version": "==6.0.1" }, "jaraco.functools": { "hashes": [ - "sha256:3b24ccb921d6b593bdceb56ce14799204f473976e2a9d4b15b04d0f2c2326664", - "sha256:d33fa765374c0611b52f8b3a795f8900869aa88c84769d4d1746cd68fb28c3e8" + "sha256:70f7e0e2ae076498e212562325e805204fc092d7b4c17e0e86c959e249701a9d", + "sha256:ad159f13428bc4acbf5541ad6dec511f91573b90fba04df61dafa2a1231cf649" ], "markers": "python_version >= '3.8'", - "version": "==4.0.1" + "version": "==4.1.0" }, "jeepney": { "hashes": [ @@ -1148,11 +1357,11 @@ }, "keyring": { "hashes": [ - "sha256:2458681cdefc0dbc0b7eb6cf75d0b98e59f9ad9b2d4edd319d18f68bdca95e50", - "sha256:daaffd42dbda25ddafb1ad5fec4024e5bbcfe424597ca1ca452b299861e49f1b" + "sha256:5426f817cf7f6f007ba5ec722b1bcad95a75b27d780343772ad76b17cb47b0bf", + "sha256:b07ebc55f3e8ed86ac81dd31ef14e81ace9dd9c3d4b5d77a6e9a2016d0d71a1b" ], "markers": "python_version >= '3.8'", - "version": "==25.2.1" + "version": "==25.4.1" }, "markdown-it-py": { "hashes": [ @@ -1164,69 +1373,70 @@ }, "markupsafe": { "hashes": [ - "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf", - "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff", - "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f", - "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3", - "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532", - "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f", - "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617", - "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df", - "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4", - "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906", - "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f", - "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4", - "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8", - "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371", - "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2", - "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465", - "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52", - "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6", - "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169", - "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad", - "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2", - "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0", - "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029", - "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f", - "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a", - "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced", - "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5", - "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c", - "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf", - "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9", - "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb", - "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad", - "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3", - "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1", - "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46", - "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc", - "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a", - "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee", - "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900", - "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5", - "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea", - "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f", - "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5", - "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e", - "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a", - "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f", - "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50", - "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a", - "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b", - "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4", - "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff", - "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2", - "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46", - "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b", - "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf", - "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5", - "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5", - "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab", - "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd", - "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68" + "sha256:0778de17cff1acaeccc3ff30cd99a3fd5c50fc58ad3d6c0e0c4c58092b859396", + "sha256:0f84af7e813784feb4d5e4ff7db633aba6c8ca64a833f61d8e4eade234ef0c38", + "sha256:17b2aea42a7280db02ac644db1d634ad47dcc96faf38ab304fe26ba2680d359a", + "sha256:242d6860f1fd9191aef5fae22b51c5c19767f93fb9ead4d21924e0bcb17619d8", + "sha256:244dbe463d5fb6d7ce161301a03a6fe744dac9072328ba9fc82289238582697b", + "sha256:26627785a54a947f6d7336ce5963569b5d75614619e75193bdb4e06e21d447ad", + "sha256:2a4b34a8d14649315c4bc26bbfa352663eb51d146e35eef231dd739d54a5430a", + "sha256:2ae99f31f47d849758a687102afdd05bd3d3ff7dbab0a8f1587981b58a76152a", + "sha256:312387403cd40699ab91d50735ea7a507b788091c416dd007eac54434aee51da", + "sha256:3341c043c37d78cc5ae6e3e305e988532b072329639007fd408a476642a89fd6", + "sha256:33d1c36b90e570ba7785dacd1faaf091203d9942bc036118fab8110a401eb1a8", + "sha256:3e683ee4f5d0fa2dde4db77ed8dd8a876686e3fc417655c2ece9a90576905344", + "sha256:3ffb4a8e7d46ed96ae48805746755fadd0909fea2306f93d5d8233ba23dda12a", + "sha256:40621d60d0e58aa573b68ac5e2d6b20d44392878e0bfc159012a5787c4e35bc8", + "sha256:40f1e10d51c92859765522cbd79c5c8989f40f0419614bcdc5015e7b6bf97fc5", + "sha256:45d42d132cff577c92bfba536aefcfea7e26efb975bd455db4e6602f5c9f45e7", + "sha256:48488d999ed50ba8d38c581d67e496f955821dc183883550a6fbc7f1aefdc170", + "sha256:4935dd7883f1d50e2ffecca0aa33dc1946a94c8f3fdafb8df5c330e48f71b132", + "sha256:4c2d64fdba74ad16138300815cfdc6ab2f4647e23ced81f59e940d7d4a1469d9", + "sha256:4c8817557d0de9349109acb38b9dd570b03cc5014e8aabf1cbddc6e81005becd", + "sha256:4ffaaac913c3f7345579db4f33b0020db693f302ca5137f106060316761beea9", + "sha256:5a4cb365cb49b750bdb60b846b0c0bc49ed62e59a76635095a179d440540c346", + "sha256:62fada2c942702ef8952754abfc1a9f7658a4d5460fabe95ac7ec2cbe0d02abc", + "sha256:67c519635a4f64e495c50e3107d9b4075aec33634272b5db1cde839e07367589", + "sha256:6a54c43d3ec4cf2a39f4387ad044221c66a376e58c0d0e971d47c475ba79c6b5", + "sha256:7044312a928a66a4c2a22644147bc61a199c1709712069a344a3fb5cfcf16915", + "sha256:730d86af59e0e43ce277bb83970530dd223bf7f2a838e086b50affa6ec5f9295", + "sha256:800100d45176652ded796134277ecb13640c1a537cad3b8b53da45aa96330453", + "sha256:80fcbf3add8790caddfab6764bde258b5d09aefbe9169c183f88a7410f0f6dea", + "sha256:82b5dba6eb1bcc29cc305a18a3c5365d2af06ee71b123216416f7e20d2a84e5b", + "sha256:852dc840f6d7c985603e60b5deaae1d89c56cb038b577f6b5b8c808c97580f1d", + "sha256:8ad4ad1429cd4f315f32ef263c1342166695fad76c100c5d979c45d5570ed58b", + "sha256:8ae369e84466aa70f3154ee23c1451fda10a8ee1b63923ce76667e3077f2b0c4", + "sha256:93e8248d650e7e9d49e8251f883eed60ecbc0e8ffd6349e18550925e31bd029b", + "sha256:973a371a55ce9ed333a3a0f8e0bcfae9e0d637711534bcb11e130af2ab9334e7", + "sha256:9ba25a71ebf05b9bb0e2ae99f8bc08a07ee8e98c612175087112656ca0f5c8bf", + "sha256:a10860e00ded1dd0a65b83e717af28845bb7bd16d8ace40fe5531491de76b79f", + "sha256:a4792d3b3a6dfafefdf8e937f14906a51bd27025a36f4b188728a73382231d91", + "sha256:a7420ceda262dbb4b8d839a4ec63d61c261e4e77677ed7c66c99f4e7cb5030dd", + "sha256:ad91738f14eb8da0ff82f2acd0098b6257621410dcbd4df20aaa5b4233d75a50", + "sha256:b6a387d61fe41cdf7ea95b38e9af11cfb1a63499af2759444b99185c4ab33f5b", + "sha256:b954093679d5750495725ea6f88409946d69cfb25ea7b4c846eef5044194f583", + "sha256:bbde71a705f8e9e4c3e9e33db69341d040c827c7afa6789b14c6e16776074f5a", + "sha256:beeebf760a9c1f4c07ef6a53465e8cfa776ea6a2021eda0d0417ec41043fe984", + "sha256:c91b394f7601438ff79a4b93d16be92f216adb57d813a78be4446fe0f6bc2d8c", + "sha256:c97ff7fedf56d86bae92fa0a646ce1a0ec7509a7578e1ed238731ba13aabcd1c", + "sha256:cb53e2a99df28eee3b5f4fea166020d3ef9116fdc5764bc5117486e6d1211b25", + "sha256:cbf445eb5628981a80f54087f9acdbf84f9b7d862756110d172993b9a5ae81aa", + "sha256:d06b24c686a34c86c8c1fba923181eae6b10565e4d80bdd7bc1c8e2f11247aa4", + "sha256:d98e66a24497637dd31ccab090b34392dddb1f2f811c4b4cd80c230205c074a3", + "sha256:db15ce28e1e127a0013dfb8ac243a8e392db8c61eae113337536edb28bdc1f97", + "sha256:db842712984e91707437461930e6011e60b39136c7331e971952bb30465bc1a1", + "sha256:e24bfe89c6ac4c31792793ad9f861b8f6dc4546ac6dc8f1c9083c7c4f2b335cd", + "sha256:e81c52638315ff4ac1b533d427f50bc0afc746deb949210bc85f05d4f15fd772", + "sha256:e9393357f19954248b00bed7c56f29a25c930593a77630c719653d51e7669c2a", + "sha256:ee3941769bd2522fe39222206f6dd97ae83c442a94c90f2b7a25d847d40f4729", + "sha256:f31ae06f1328595d762c9a2bf29dafd8621c7d3adc130cbb46278079758779ca", + "sha256:f94190df587738280d544971500b9cafc9b950d32efcb1fba9ac10d84e6aa4e6", + "sha256:fa7d686ed9883f3d664d39d5a8e74d3c5f63e603c2e3ff0abcba23eac6542635", + "sha256:fb532dd9900381d2e8f48172ddc5a59db4c445a11b9fab40b3b786da40d3b56b", + "sha256:fe32482b37b4b00c7a52a07211b479653b7fe4f22b2e481b9a9b099d8a430f2f" ], - "markers": "python_version >= '3.7'", - "version": "==2.1.5" + "markers": "python_version >= '3.9'", + "version": "==3.0.1" }, "mdurl": { "hashes": [ @@ -1238,48 +1448,48 @@ }, "more-itertools": { "hashes": [ - "sha256:686b06abe565edfab151cb8fd385a05651e1fdf8f0a14191e4439283421f8684", - "sha256:8fccb480c43d3e99a00087634c06dd02b0d50fbf088b380de5a41a015ec239e1" + "sha256:037b0d3203ce90cca8ab1defbbdac29d5f993fc20131f3664dc8d6acfa872aef", + "sha256:5482bfef7849c25dc3c6dd53a6173ae4795da2a41a80faea6700d9f5846c5da6" ], "markers": "python_version >= '3.8'", - "version": "==10.2.0" + "version": "==10.5.0" }, "nh3": { "hashes": [ - "sha256:0316c25b76289cf23be6b66c77d3608a4fdf537b35426280032f432f14291b9a", - "sha256:1a814dd7bba1cb0aba5bcb9bebcc88fd801b63e21e2450ae6c52d3b3336bc911", - "sha256:1aa52a7def528297f256de0844e8dd680ee279e79583c76d6fa73a978186ddfb", - "sha256:22c26e20acbb253a5bdd33d432a326d18508a910e4dcf9a3316179860d53345a", - "sha256:40015514022af31975c0b3bca4014634fa13cb5dc4dbcbc00570acc781316dcc", - "sha256:40d0741a19c3d645e54efba71cb0d8c475b59135c1e3c580f879ad5514cbf028", - "sha256:551672fd71d06cd828e282abdb810d1be24e1abb7ae2543a8fa36a71c1006fe9", - "sha256:66f17d78826096291bd264f260213d2b3905e3c7fae6dfc5337d49429f1dc9f3", - "sha256:85cdbcca8ef10733bd31f931956f7fbb85145a4d11ab9e6742bbf44d88b7e351", - "sha256:a3f55fabe29164ba6026b5ad5c3151c314d136fd67415a17660b4aaddacf1b10", - "sha256:b4427ef0d2dfdec10b641ed0bdaf17957eb625b2ec0ea9329b3d28806c153d71", - "sha256:ba73a2f8d3a1b966e9cdba7b211779ad8a2561d2dba9674b8a19ed817923f65f", - "sha256:c21bac1a7245cbd88c0b0e4a420221b7bfa838a2814ee5bb924e9c2f10a1120b", - "sha256:c551eb2a3876e8ff2ac63dff1585236ed5dfec5ffd82216a7a174f7c5082a78a", - "sha256:c790769152308421283679a142dbdb3d1c46c79c823008ecea8e8141db1a2062", - "sha256:d7a25fd8c86657f5d9d576268e3b3767c5cd4f42867c9383618be8517f0f022a" - ], - "version": "==0.2.17" + "sha256:0411beb0589eacb6734f28d5497ca2ed379eafab8ad8c84b31bb5c34072b7164", + "sha256:14c5a72e9fe82aea5fe3072116ad4661af5cf8e8ff8fc5ad3450f123e4925e86", + "sha256:19aaba96e0f795bd0a6c56291495ff59364f4300d4a39b29a0abc9cb3774a84b", + "sha256:34c03fa78e328c691f982b7c03d4423bdfd7da69cd707fe572f544cf74ac23ad", + "sha256:36c95d4b70530b320b365659bb5034341316e6a9b30f0b25fa9c9eff4c27a204", + "sha256:3a157ab149e591bb638a55c8c6bcb8cdb559c8b12c13a8affaba6cedfe51713a", + "sha256:42c64511469005058cd17cc1537578eac40ae9f7200bedcfd1fc1a05f4f8c200", + "sha256:5f36b271dae35c465ef5e9090e1fdaba4a60a56f0bb0ba03e0932a66f28b9189", + "sha256:6955369e4d9f48f41e3f238a9e60f9410645db7e07435e62c6a9ea6135a4907f", + "sha256:7b7c2a3c9eb1a827d42539aa64091640bd275b81e097cd1d8d82ef91ffa2e811", + "sha256:8ce0f819d2f1933953fca255db2471ad58184a60508f03e6285e5114b6254844", + "sha256:94a166927e53972a9698af9542ace4e38b9de50c34352b962f4d9a7d4c927af4", + "sha256:a7f1b5b2c15866f2db413a3649a8fe4fd7b428ae58be2c0f6bca5eefd53ca2be", + "sha256:c8b3a1cebcba9b3669ed1a84cc65bf005728d2f0bc1ed2a6594a992e817f3a50", + "sha256:de3ceed6e661954871d6cd78b410213bdcb136f79aafe22aa7182e028b8c7307", + "sha256:f0eca9ca8628dbb4e916ae2491d72957fdd35f7a5d326b7032a345f111ac07fe" + ], + "version": "==0.2.18" }, "packaging": { "hashes": [ - "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5", - "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9" + "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002", + "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124" ], - "markers": "python_version >= '3.7'", - "version": "==24.0" + "markers": "python_version >= '3.8'", + "version": "==24.1" }, "pkginfo": { "hashes": [ - "sha256:6d4998d1cd42c297af72cc0eab5f5bab1d356fb8a55b828fa914173f8bc1ba05", - "sha256:dba885aa82e31e80d615119874384923f4e011c2a39b0c4b7104359e36cb7087" + "sha256:5df73835398d10db79f8eecd5cd86b1f6d29317589ea70796994d49399af6297", + "sha256:889a6da2ed7ffc58ab5b900d888ddce90bce912f2d2de1dc1c26f4cb9fe65097" ], - "markers": "python_version >= '3.8'", - "version": "==1.11.0" + "markers": "python_version >= '3.6'", + "version": "==1.10.0" }, "pluggy": { "hashes": [ @@ -1307,27 +1517,28 @@ }, "pyproject-hooks": { "hashes": [ - "sha256:4b37730834edbd6bd37f26ece6b44802fb1c1ee2ece0e54ddff8bfc06db86965", - "sha256:7ceeefe9aec63a1064c18d939bdc3adf2d8aa1988a510afec15151578b232aa2" + "sha256:1e859bd5c40fae9448642dd871adf459e5e2084186e8d2c2a79a824c970da1f8", + "sha256:9e5c6bfa8dcc30091c74b0cf803c81fdd29d94f01992a7707bc97babb1141913" ], "markers": "python_version >= '3.7'", - "version": "==1.1.0" + "version": "==1.2.0" }, "pytest": { "hashes": [ - "sha256:c434598117762e2bd304e526244f67bf66bbd7b5d6cf22138be51ff661980343", - "sha256:de4bb8104e201939ccdc688b27a89a7be2079b22e2bd2b07f806b6ba71117977" + "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181", + "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2" ], "index": "pypi", - "version": "==8.2.2" + "markers": "python_version >= '3.8'", + "version": "==8.3.3" }, "readme-renderer": { "hashes": [ - "sha256:1818dd28140813509eeed8d62687f7cd4f7bad90d4db586001c5dc09d4fde311", - "sha256:19db308d86ecd60e5affa3b2a98f017af384678c63c88e5d4556a380e674f3f9" + "sha256:2fbca89b81a08526aadf1357a8c2ae889ec05fb03f5da67f9769c9a592166151", + "sha256:8712034eabbfa6805cacf1402b4eeb2a73028f72d1166d6f5cb7f9c047c5d1e1" ], - "markers": "python_version >= '3.8'", - "version": "==43.0" + "markers": "python_version >= '3.9'", + "version": "==44.0" }, "requests": { "hashes": [ @@ -1335,6 +1546,7 @@ "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6" ], "index": "pypi", + "markers": "python_version >= '3.8'", "version": "==2.32.3" }, "requests-mock": { @@ -1343,6 +1555,7 @@ "sha256:e9e12e333b525156e82a3c852f22016b9158220d2f47454de9cae8a77d371401" ], "index": "pypi", + "markers": "python_version >= '3.5'", "version": "==1.12.1" }, "requests-toolbelt": { @@ -1363,11 +1576,11 @@ }, "rich": { "hashes": [ - "sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222", - "sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432" + "sha256:51a2c62057461aaf7152b4d611168f93a9fc73068f8ded2790f29fe2b5366d0c", + "sha256:8c82a3d3f8dcfe9e734771313e606b39d8247bb6b826e196f4914b333b743cf1" ], - "markers": "python_full_version >= '3.7.0'", - "version": "==13.7.1" + "markers": "python_full_version >= '3.8.0'", + "version": "==13.9.2" }, "secretstorage": { "hashes": [ @@ -1379,11 +1592,12 @@ }, "setuptools": { "hashes": [ - "sha256:54faa7f2e8d2d11bcd2c07bed282eef1046b5c080d1c32add737d7b5817b1ad4", - "sha256:f211a66637b8fa059bb28183da127d4e86396c991a942b028c6650d4319c3fd0" + "sha256:35ab7fd3bcd95e6b7fd704e4a1539513edad446c097797f2985e0e4b960772f2", + "sha256:d59a21b17a275fb872a9c3dae73963160ae079f1049ed956880cd7c09b120538" ], "index": "pypi", - "version": "==70.0.0" + "markers": "python_version >= '3.8'", + "version": "==75.1.0" }, "snowballstemmer": { "hashes": [ @@ -1394,19 +1608,19 @@ }, "soupsieve": { "hashes": [ - "sha256:5663d5a7b3bfaeee0bc4372e7fc48f9cff4940b3eec54a6451cc5299f1097690", - "sha256:eaa337ff55a1579b6549dc679565eac1e3d000563bcb1c8ab0d0fefbc0c2cdc7" + "sha256:e2e68417777af359ec65daac1057404a3c8a5455bb8abc36f1a9866ab1a51abb", + "sha256:e72c4ff06e4fb6e4b5a9f0f55fe6e81514581fca1515028625d0f299c602ccc9" ], "markers": "python_version >= '3.8'", - "version": "==2.5" + "version": "==2.6" }, "sphinx": { "hashes": [ - "sha256:413f75440be4cacf328f580b4274ada4565fb2187d696a84970c23f77b64d8c3", - "sha256:a4a7db75ed37531c05002d56ed6948d4c42f473a36f46e1382b0bd76ca9627bc" + "sha256:0cce1ddcc4fd3532cf1dd283bc7d886758362c5c1de6598696579ce96d8ffa5b", + "sha256:56173572ae6c1b9a38911786e206a110c9749116745873feae4f9ce88e59391d" ], - "markers": "python_version >= '3.9'", - "version": "==7.3.7" + "markers": "python_version >= '3.10'", + "version": "==8.0.2" }, "sphinx-basic-ng": { "hashes": [ @@ -1418,27 +1632,27 @@ }, "sphinxcontrib-applehelp": { "hashes": [ - "sha256:c40a4f96f3776c4393d933412053962fac2b84f4c99a7982ba42e09576a70619", - "sha256:cb61eb0ec1b61f349e5cc36b2028e9e7ca765be05e49641c97241274753067b4" + "sha256:2f29ef331735ce958efa4734873f084941970894c6090408b079c61b2e1c06d1", + "sha256:4cd3f0ec4ac5dd9c17ec65e9ab272c9b867ea77425228e68ecf08d6b28ddbdb5" ], "markers": "python_version >= '3.9'", - "version": "==1.0.8" + "version": "==2.0.0" }, "sphinxcontrib-devhelp": { "hashes": [ - "sha256:6485d09629944511c893fa11355bda18b742b83a2b181f9a009f7e500595c90f", - "sha256:9893fd3f90506bc4b97bdb977ceb8fbd823989f4316b28c3841ec128544372d3" + "sha256:411f5d96d445d1d73bb5d52133377b4248ec79db5c793ce7dbe59e074b4dd1ad", + "sha256:aefb8b83854e4b0998877524d1029fd3e6879210422ee3780459e28a1f03a8a2" ], "markers": "python_version >= '3.9'", - "version": "==1.0.6" + "version": "==2.0.0" }, "sphinxcontrib-htmlhelp": { "hashes": [ - "sha256:0dc87637d5de53dd5eec3a6a01753b1ccf99494bd756aafecd74b4fa9e729015", - "sha256:393f04f112b4d2f53d93448d4bce35842f62b307ccdc549ec1585e950bc35e04" + "sha256:166759820b47002d22914d64a075ce08f4c46818e17cfc9470a9786b759b19f8", + "sha256:c9e2916ace8aad64cc13a0d233ee22317f2b9025b9cf3295249fa985cc7082e9" ], "markers": "python_version >= '3.9'", - "version": "==2.0.5" + "version": "==2.1.0" }, "sphinxcontrib-jsmath": { "hashes": [ @@ -1450,43 +1664,44 @@ }, "sphinxcontrib-qthelp": { "hashes": [ - "sha256:053dedc38823a80a7209a80860b16b722e9e0209e32fea98c90e4e6624588ed6", - "sha256:e2ae3b5c492d58fcbd73281fbd27e34b8393ec34a073c792642cd8e529288182" + "sha256:4fe7d0ac8fc171045be623aba3e2a8f613f8682731f9153bb2e40ece16b9bbab", + "sha256:b18a828cdba941ccd6ee8445dbe72ffa3ef8cbe7505d8cd1fa0d42d3f2d5f3eb" ], "markers": "python_version >= '3.9'", - "version": "==1.0.7" + "version": "==2.0.0" }, "sphinxcontrib-serializinghtml": { "hashes": [ - "sha256:326369b8df80a7d2d8d7f99aa5ac577f51ea51556ed974e7716cfd4fca3f6cb7", - "sha256:93f3f5dc458b91b192fe10c397e324f262cf163d79f3282c158e8436a2c4511f" + "sha256:6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331", + "sha256:e9d912827f872c029017a53f0ef2180b327c3f7fd23c87229f7a8e8b70031d4d" ], "markers": "python_version >= '3.9'", - "version": "==1.1.10" + "version": "==2.0.0" }, "twine": { "hashes": [ - "sha256:4d74770c88c4fcaf8134d2a6a9d863e40f08255ff7d8e2acb3cbbd57d25f6e9d", - "sha256:fe1d814395bfe50cfbe27783cb74efe93abeac3f66deaeb6c8390e4e92bacb43" + "sha256:215dbe7b4b94c2c50a7315c0275d2258399280fbb7d04182c7e55e24b5f93997", + "sha256:9aa0825139c02b3434d913545c7b847a21c835e11597f5255842d457da2322db" ], "index": "pypi", - "version": "==5.1.0" + "markers": "python_version >= '3.8'", + "version": "==5.1.1" }, "urllib3": { "hashes": [ - "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d", - "sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19" + "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac", + "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9" ], "markers": "python_version >= '3.8'", - "version": "==2.2.1" + "version": "==2.2.3" }, "zipp": { "hashes": [ - "sha256:bf1dcf6450f873a13e952a29504887c89e6de7506209e5b1bcc3460135d4de19", - "sha256:f091755f667055f2d02b32c53771a7a6c8b47e1fdbc4b72a8b9072b3eef8015c" + "sha256:a817ac80d6cf4b23bf7f2828b7cabf326f15a001bea8b1f9b49631780ba28350", + "sha256:bc9eb26f4506fda01b81bcde0ca78103b6e62f991b381fec825435c836edbc29" ], "markers": "python_version >= '3.8'", - "version": "==3.19.2" + "version": "==3.20.2" } } } diff --git a/lib/python/README.md b/lib/python/README.md index 96166554a7f5cf5a1c3cb1d3fa76650f970eb8bf..ccf6e82dd14db37362a3b87ac6fe605c14f4e9de 100644 --- a/lib/python/README.md +++ b/lib/python/README.md @@ -48,17 +48,17 @@ client.import_table_data(database_id=7, table_id=13, file_name_or_data_frame=df) ## Supported Features & Best-Practices - Manage user - account ([docs](https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.4.5/api/#create-user-account)) + account ([docs](https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.4.7/api/#create-user-account)) - Manage databases ([docs](https://www.ifs.tuwien.ac.at/infrastructures/dbrepo//usage-overview/#create-database)) - Manage database access & - visibility ([docs](https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.4.5/api/#create-database)) + visibility ([docs](https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.4.7/api/#create-database)) - Import - dataset ([docs](https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.4.5/api/#import-dataset)) + dataset ([docs](https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.4.7/api/#import-dataset)) - Create persistent - identifiers ([docs](https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.4.5/api/#assign-database-pid)) + identifiers ([docs](https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.4.7/api/#assign-database-pid)) - Execute - queries ([docs](https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.4.5/api/#export-subset)) + queries ([docs](https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.4.7/api/#export-subset)) - Get data from tables/views/subsets ## Configure diff --git a/lib/python/dbrepo/AmqpClient.py b/lib/python/dbrepo/AmqpClient.py index 1cc0e0319c03e46935a5ea9a21a963b609242726..cd0b1140996d0572586985ee0eb2e1285e556c27 100644 --- a/lib/python/dbrepo/AmqpClient.py +++ b/lib/python/dbrepo/AmqpClient.py @@ -1,13 +1,13 @@ -import dataclasses import os import pika import sys import json import logging -from dbrepo.api.dto import CreateData +from dbrepo.api.exceptions import AuthenticationError -logger = logging.getLogger("AmqpClient") +logging.basicConfig(format='%(asctime)s %(name)-12s %(levelname)-6s %(message)s', level=logging.INFO, + stream=sys.stdout) class AmqpClient: @@ -16,9 +16,9 @@ class AmqpClient: via environment variables, e.g. set endpoint with DBREPO_ENDPOINT. You can override the constructor parameters \ with the environment variables. - :param broker_host: The AMQP API host. Optional. Default: "broker-service" - :param broker_port: The AMQP API port. Optional. Default: 5672 - :param broker_virtual_host: The AMQP API virtual host. Optional. Default: "/" + :param broker_host: The AMQP API host. Optional. Default: "localhost". + :param broker_port: The AMQP API port. Optional. Default: 5672, + :param broker_virtual_host: The AMQP API virtual host. Optional. Default: "dbrepo". :param username: The AMQP API username. Optional. :param password: The AMQP API password. Optional. """ @@ -29,13 +29,11 @@ class AmqpClient: password: str = None def __init__(self, - broker_host: str = 'broker-service', + broker_host: str = 'localhost', broker_port: int = 5672, - broker_virtual_host: str = '/', + broker_virtual_host: str = 'dbrepo', username: str = None, password: str = None) -> None: - logging.basicConfig(format='%(asctime)s %(name)-12s %(levelname)-6s %(message)s', level=logging.DEBUG, - stream=sys.stdout) self.broker_host = os.environ.get('AMQP_API_HOST', broker_host) self.broker_port = os.environ.get('AMQP_API_PORT', broker_port) if os.environ.get('AMQP_API_VIRTUAL_HOST') is not None: @@ -45,20 +43,21 @@ class AmqpClient: self.username = os.environ.get('AMQP_API_USERNAME', username) self.password = os.environ.get('AMQP_API_PASSWORD', password) - def publish(self, exchange: str, routing_key: str, data=dict) -> None: + def publish(self, routing_key: str, data=dict, exchange: str = 'dbrepo') -> None: """ Publishes data to a given exchange with the given routing key with a blocking connection. - :param exchange: The exchange name. :param routing_key: The routing key. :param data: The data. + :param exchange: The exchange name. Default: "dbrepo". """ + if self.username is None or self.password is None: + raise AuthenticationError(f"Failed to perform request: authentication required") parameters = pika.ConnectionParameters(host=self.broker_host, port=self.broker_port, virtual_host=self.broker_virtual_host, credentials=pika.credentials.PlainCredentials(self.username, self.password)) connection = pika.BlockingConnection(parameters) channel = connection.channel() - channel.basic_publish(exchange=exchange, routing_key=routing_key, - body=json.dumps(data)) + channel.basic_publish(exchange=exchange, routing_key=routing_key, body=json.dumps(data)) connection.close() diff --git a/lib/python/dbrepo/RestClient.py b/lib/python/dbrepo/RestClient.py index 6be85146a97763e32b95a6272c9758dff46d4d77..8e0e782bb88055e8bc34a8ae8afb46aea0cb30f7 100644 --- a/lib/python/dbrepo/RestClient.py +++ b/lib/python/dbrepo/RestClient.py @@ -14,7 +14,8 @@ from dbrepo.api.exceptions import ResponseCodeError, UsernameExistsError, EmailE ForbiddenError, MalformedError, NameExistsError, QueryStoreError, ExternalSystemError, \ AuthenticationError, UploadError, FormatNotAvailable, RequestError, ServiceError, ServiceConnectionError -logger = logging.getLogger("RestClient") +logging.basicConfig(format='%(asctime)s %(name)-12s %(levelname)-6s %(message)s', level=logging.INFO, + stream=sys.stdout) class RestClient: @@ -39,8 +40,6 @@ class RestClient: username: str = None, password: str = None, secure: bool = True) -> None: - logging.basicConfig(format='%(asctime)s %(name)-12s %(levelname)-6s %(message)s', level=logging.DEBUG, - stream=sys.stdout) self.endpoint = os.environ.get('REST_API_ENDPOINT', endpoint) self.username = os.environ.get('REST_API_USERNAME', username) self.password = os.environ.get('REST_API_PASSWORD', password) @@ -48,7 +47,7 @@ class RestClient: self.secure = os.environ.get('REST_API_SECURE') == 'True' else: self.secure = secure - logger.debug( + logging.debug( f'initialized rest client with endpoint={self.endpoint}, username={username}, verify_ssl={secure}') def _wrapper(self, method: str, url: str, params: [(str,)] = None, payload=None, headers: dict = None, @@ -56,27 +55,27 @@ class RestClient: if force_auth and (self.username is None and self.password is None): raise AuthenticationError(f"Failed to perform request: authentication required") url = f'{self.endpoint}{url}' - logger.debug(f'method: {method}') - logger.debug(f'url: {url}') + logging.debug(f'method: {method}') + logging.debug(f'url: {url}') if params is not None: - logger.debug(f'params: {params}') + logging.debug(f'params: {params}') if stream is not None: - logger.debug(f'stream: {stream}') - logger.debug(f'secure: {self.secure}') + logging.debug(f'stream: {stream}') + logging.debug(f'secure: {self.secure}') if headers is not None: - logger.debug(f'headers: {headers}') + logging.debug(f'headers: {headers}') else: headers = dict() - logger.debug(f'no headers set') + logging.debug(f'no headers set') if payload is not None: payload = payload.model_dump() auth = None if self.username is None and self.password is not None: headers["Authorization"] = f"Bearer {self.password}" - logger.debug(f'configured for oidc/bearer auth') + logging.debug(f'configured for oidc/bearer auth') elif self.username is not None and self.password is not None: auth = (self.username, self.password) - logger.debug(f'configured for basic auth: username={self.username}, password=(hidden)') + logging.debug(f'configured for basic auth: username={self.username}, password=(hidden)') return requests.request(method=method, url=url, auth=auth, verify=self.secure, json=payload, headers=headers, params=params, stream=stream) @@ -1104,10 +1103,11 @@ class RestClient: def import_table_data(self, database_id: int, table_id: int, file_name_or_data_frame: str | DataFrame, separator: str = ",", quote: str = "\"", skip_lines: int = 0, - false_encoding: str = None, true_encoding: str = None, null_encoding: str = None, line_encoding: str = "\n") -> None: """ - Import a csv dataset from a file into a table in a database with given database id and table id. + Import a csv dataset from a file into a table in a database with given database id and table id. ATTENTION: + the import is column-ordering sensitive! The csv dataset must have the same columns in the same order as the + target table. :param database_id: The database id. :param table_id: The table id. @@ -1115,9 +1115,6 @@ class RestClient: :param separator: The csv column separator. Optional. :param quote: The column data quotation character. Optional. :param skip_lines: The number of lines to skip. Optional. Default: 0. - :param false_encoding: The encoding of boolean false. Optional. - :param true_encoding: The encoding of boolean true. Optional. - :param null_encoding: The encoding of null. Optional. :param line_encoding: The encoding of the line termination. Optional. Default: CR (Windows). :raises MalformedError: If the payload is rejected by the service (e.g. LOB could not be imported). @@ -1137,9 +1134,7 @@ class RestClient: url = f'/api/database/{database_id}/table/{table_id}/data/import' response = self._wrapper(method="post", url=url, force_auth=True, payload=Import(location=filename, separator=separator, quote=quote, - skip_lines=skip_lines, false_element=false_encoding, - true_element=true_encoding, null_element=null_encoding, - line_termination=line_encoding)) + skip_lines=skip_lines, line_termination=line_encoding)) if response.status_code == 202: return if response.status_code == 400: @@ -1556,7 +1551,7 @@ class RestClient: f'201 (CREATED): {response.text}') def create_subset(self, database_id: int, query: str, page: int = 0, size: int = 10, - df: bool = False) -> Result | DataFrame: + timestamp: datetime.datetime = None, df: bool = False) -> Result | DataFrame: """ Executes a SQL query in a database where the current user has at least read access with given database id. The result set can be paginated with setting page and size (both). Historic data can be queried by setting @@ -1566,6 +1561,7 @@ class RestClient: :param query: The query statement. :param page: The result pagination number. Optional. Default: 0. :param size: The result pagination size. Optional. Default: 10. + :param timestamp: The timestamp at which the data validity is set. Optional. Default: <current timestamp>. :param df: If true, the result is returned as Pandas DataFrame. Optional. Default: False. :returns: The result set, if successful. @@ -1581,7 +1577,12 @@ class RestClient: url = f'/api/database/{database_id}/subset' if page is not None and size is not None: url += f'?page={page}&size={size}' - response = self._wrapper(method="post", url=url, force_auth=True, headers={"Accept": "application/json"}, + if timestamp is not None: + url += f'×tamp={timestamp.strftime("%Y-%m-%dT%H:%M:%SZ")}' + else: + if timestamp is not None: + url += f'?timestamp={timestamp.strftime("%Y-%m-%dT%H:%M:%SZ")}' + response = self._wrapper(method="post", url=url, headers={"Accept": "application/json"}, payload=ExecuteQuery(statement=query)) if response.status_code == 201: body = response.json() diff --git a/lib/python/dbrepo/UploadClient.py b/lib/python/dbrepo/UploadClient.py index 05fa133d64b2be902deb81423fef9bdc07e8c66d..b0bc90fc00aa1810d4e80873b9e8583ff1a4e5be 100644 --- a/lib/python/dbrepo/UploadClient.py +++ b/lib/python/dbrepo/UploadClient.py @@ -4,7 +4,8 @@ import re import sys from tusclient import client -logger = logging.getLogger("UploadClient") +logging.basicConfig(format='%(asctime)s %(name)-12s %(levelname)-6s %(message)s', level=logging.INFO, + stream=sys.stdout) class UploadClient: @@ -18,8 +19,6 @@ class UploadClient: endpoint: str = None def __init__(self, endpoint: str = 'http://gateway-service/api/upload/files') -> None: - logging.basicConfig(format='%(asctime)s %(name)-12s %(levelname)-6s %(message)s', level=logging.DEBUG, - stream=sys.stdout) self.endpoint = os.environ.get('REST_UPLOAD_ENDPOINT', endpoint) def upload(self, file_path: str) -> str: @@ -30,10 +29,11 @@ class UploadClient: :returns: Filename on the Storage Service, if successful. """ + logging.debug(f"upload file to endpoint: {self.endpoint}") tus_client = client.TusClient(url=self.endpoint) uploader = tus_client.uploader(file_path=file_path) uploader.upload() m = re.search('\\/([a-f0-9]+)\\+', uploader.url) filename = m.group(0)[1:-1] - logger.debug(f'uploaded file {file_path} to storage service with key: {filename}') + logging.info(f'Uploaded file {file_path} to storage service with key: {filename}') return filename diff --git a/lib/python/dbrepo/api/dto.py b/lib/python/dbrepo/api/dto.py index c601125767c2065e62062c9c82e39ad402ee5bc8..fc97c2b8d731b064e2d8ff7a77e458e727f95f3c 100644 --- a/lib/python/dbrepo/api/dto.py +++ b/lib/python/dbrepo/api/dto.py @@ -11,14 +11,6 @@ Timestamp = Annotated[ ] -class ImageDate(BaseModel): - id: int - database_format: str - unix_format: str - has_time: bool - created_at: Timestamp - - class JwtAuth(BaseModel): access_token: str refresh_token: str @@ -40,7 +32,7 @@ class Image(BaseModel): driver_class: str jdbc_method: str default_port: int - date_formats: Optional[List[ImageDate]] = field(default_factory=list) + data_types: List[DataType] = field(default_factory=list) class ImageBrief(BaseModel): @@ -193,6 +185,7 @@ class ColumnType(str, Enum): LONGTEXT = "longtext" LONGBLOB = "longblob" ENUM = "enum" + SERIAL = "serial" SET = "set" BIT = "bit" TINYINT = "tinyint" @@ -487,9 +480,6 @@ class Import(BaseModel): separator: str quote: Optional[str] = None skip_lines: Optional[int] = None - false_element: Optional[bool] = None - true_element: Optional[bool] = None - null_element: Optional[str] = None line_termination: Optional[str] = None @@ -522,7 +512,6 @@ class CreateTableColumn(BaseModel): index_length: Optional[int] = None size: Optional[int] = None d: Optional[int] = None - dfid: Optional[int] = None enums: Optional[List[str]] = None sets: Optional[List[str]] = None @@ -885,13 +874,30 @@ class UpdateQuery(BaseModel): persist: bool +class DataType(BaseModel): + display_name: str + value: str + documentation: str + is_quoted: bool + is_buildable: bool + size_min: Optional[int] = None + size_max: Optional[int] = None + size_default: Optional[int] = None + size_required: Optional[bool] = None + d_min: Optional[int] = None + d_max: Optional[int] = None + d_default: Optional[int] = None + d_required: Optional[bool] = None + data_hint: Optional[str] = None + type_hint: Optional[str] = None + + class Column(BaseModel): id: int name: str database_id: int table_id: int internal_name: str - auto_generated: bool column_type: ColumnType is_public: bool is_null_allowed: bool @@ -905,7 +911,6 @@ class Column(BaseModel): unit: Optional[Unit] = None enums: Optional[List[str]] = field(default_factory=list) sets: Optional[List[str]] = field(default_factory=list) - date_format: Optional[ImageDate] = None index_length: Optional[int] = None length: Optional[int] = None data_length: Optional[int] = None @@ -921,7 +926,6 @@ class ViewColumn(BaseModel): name: str database_id: int internal_name: str - auto_generated: bool column_type: ColumnType is_public: bool is_null_allowed: bool @@ -932,7 +936,6 @@ class ViewColumn(BaseModel): median: Optional[float] = None concept: Optional[Concept] = None unit: Optional[Unit] = None - date_format: Optional[ImageDate] = None index_length: Optional[int] = None length: Optional[int] = None diff --git a/lib/python/docs/index.rst b/lib/python/docs/index.rst index 688a62683170012b263ffc1df234c881323ab9fb..d535a0b2d359e13ca02bee2ecc12cbfb3d3d0bce 100644 --- a/lib/python/docs/index.rst +++ b/lib/python/docs/index.rst @@ -12,7 +12,7 @@ Quickstart ---------- Find numerous quickstart examples on -the `DBRepo website <https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.4.5/api/>`_. +the `DBRepo website <https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.4.7/api/>`_. AMQP API Client ----------- diff --git a/lib/python/pyproject.toml b/lib/python/pyproject.toml index 8c89061ce82d02b398c4c45f14a5b43efa64ac15..4e6642658bab6423df8db412f529021104e532fd 100644 --- a/lib/python/pyproject.toml +++ b/lib/python/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "dbrepo" -version = "1.4.6" +version = "1.4.7" description = "DBRepo Python Library" keywords = [ "DBRepo", @@ -34,7 +34,7 @@ requires = [ build-backend = "setuptools.build_meta" [project.urls] -Homepage = "https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.4.4/" -Documentation = "https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.4.4/python/" +Homepage = "https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.4.7/" +Documentation = "https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.4.7/python/" Issues = "https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/issues" Source = "https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/" \ No newline at end of file diff --git a/lib/python/setup.py b/lib/python/setup.py index 34c44d115b6169e64f356b8d9593a65b59ab2bb1..8d686818235b9ca80e1f9f2bcb83765ee8a912d6 100644 --- a/lib/python/setup.py +++ b/lib/python/setup.py @@ -2,9 +2,9 @@ from distutils.core import setup setup(name="dbrepo", - version="1.4.6", + version="1.4.7", description="A library for communicating with DBRepo", - url="https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.4.5/", + url="https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.4.7/", author="Martin Weise", license="Apache-2.0", author_email="martin.weise@tuwien.ac.at", diff --git a/lib/python/test.sh b/lib/python/test.sh index 532d9a58d1a981cbd070f371ebf6dfaea7757c20..cd0129654a468e4aa0d9bec0b1ba3b04f193fd24 100644 --- a/lib/python/test.sh +++ b/lib/python/test.sh @@ -1,3 +1,3 @@ #!/bin/bash source ./lib/python/venv/bin/activate -cd ./lib/python/ && coverage run -m pytest tests/*.py --junitxml=report.xml && coverage html --omit="test/*" && coverage report --omit="test/*" > ./coverage.txt \ No newline at end of file +cd ./lib/python/ && coverage run -m pytest tests/*.py --junitxml=report.xml && coverage html && coverage report > ./coverage.txt \ No newline at end of file diff --git a/lib/python/tests/test_unit_container.py b/lib/python/tests/test_unit_container.py index 8f3297879ada5fcf416cc8afc508d059cf28c95d..0e1d93faa0e9b1c598afcede5ad71c7e08ef9767 100644 --- a/lib/python/tests/test_unit_container.py +++ b/lib/python/tests/test_unit_container.py @@ -4,11 +4,9 @@ import requests_mock import datetime from dbrepo.RestClient import RestClient -from dbrepo.api.dto import Container, Image, ContainerBrief, ImageBrief +from dbrepo.api.dto import Container, Image, ContainerBrief, ImageBrief, DataType from dbrepo.api.exceptions import ResponseCodeError, NotExistsError -from dbrepo.api.dto import ImageDate - class ContainerUnitTest(unittest.TestCase): @@ -69,29 +67,10 @@ class ContainerUnitTest(unittest.TestCase): dialect="org.hibernate.dialect.MariaDBDialect", driver_class="org.mariadb.jdbc.Driver", jdbc_method="mariadb", - date_formats=[ - ImageDate(id=1, - example="2024-03-26 10:26:00", - database_format="%Y-%c-%d %H:%i:%S", - unix_format="yyyy-MM-dd HH:mm:ss", - has_time=True, - created_at=datetime.datetime(2024, 3, 26, 10, 26, 0, 0, - datetime.timezone.utc)), - ImageDate(id=2, - example="2024-03-26", - database_format="%Y-%c-%d", - unix_format="yyyy-MM-dd", - has_time=False, - created_at=datetime.datetime(2024, 3, 26, 0, 0, 0, 0, - datetime.timezone.utc)), - ImageDate(id=3, - example="10:25:01", - database_format="%Y-%c-%d", - unix_format="yyyy-MM-dd", - has_time=False, - created_at=datetime.datetime(2024, 3, 26, 0, 0, 0, 0, - datetime.timezone.utc)), - ]), + data_types=[ + DataType(display_name="SERIAL", value="serial", + documentation="https://mariadb.com/kb/en/bigint/", + is_quoted=False, is_buildable=True)]), hash="f829dd8a884182d0da846f365dee1221fd16610a14c81b8f9f295ff162749e50") # mock mock.get('/api/container/1', json=exp.model_dump()) diff --git a/lib/python/tests/test_unit_database.py b/lib/python/tests/test_unit_database.py index dea15691e22a990434772c433683eb6eefc0b253..f72c80c93c0497eb0d2d6f68e2ab8029cccb2aec 100644 --- a/lib/python/tests/test_unit_database.py +++ b/lib/python/tests/test_unit_database.py @@ -7,11 +7,9 @@ from pydantic_core import ValidationError from dbrepo.RestClient import RestClient from dbrepo.api.dto import Database, User, Container, Image, UserAttributes, DatabaseAccess, AccessType, DatabaseBrief, \ - UserBrief + UserBrief, DataType from dbrepo.api.exceptions import ResponseCodeError, NotExistsError, ForbiddenError, MalformedError, AuthenticationError -from dbrepo.api.dto import ImageDate - class DatabaseUnitTest(unittest.TestCase): @@ -72,7 +70,11 @@ class DatabaseUnitTest(unittest.TestCase): dialect='org.hibernate.dialect.MariaDBDialect', driver_class='org.mariadb.jdbc.Driver', jdbc_method='mariadb', - default_port=3306 + default_port=3306, + data_types=[ + DataType(display_name="SERIAL", value="serial", + documentation="https://mariadb.com/kb/en/bigint/", + is_quoted=False, is_buildable=True)] ) ) ) diff --git a/lib/python/tests/test_unit_query.py b/lib/python/tests/test_unit_query.py index d2de6f8278bc33a123cf38525493ec93532ce87a..e1b326fa576b86519e6c059abd73f66dacbda2e5 100644 --- a/lib/python/tests/test_unit_query.py +++ b/lib/python/tests/test_unit_query.py @@ -1,6 +1,4 @@ import unittest -from json import dumps -from typing import Any import requests_mock import datetime @@ -64,16 +62,19 @@ class QueryUnitTest(unittest.TestCase): except NotExistsError: pass - def test_create_subset_not_auth_fails(self): + def test_create_subset_not_auth_succeeds(self): with requests_mock.Mocker() as mock: + exp = Result(result=[{'id': 1, 'username': 'foo'}, {'id': 2, 'username': 'bar'}], + headers=[{'id': 0, 'username': 1}], + id=None) # mock - mock.post('/api/database/1/subset', status_code=417) + mock.post('/api/database/1/subset', json=exp.model_dump(), status_code=201) # test - try: - response = RestClient().create_subset(database_id=1, - query="SELECT id, username FROM some_table WHERE id IN (1,2)") - except AuthenticationError: - pass + + client = RestClient() + response = client.create_subset(database_id=1, page=0, size=10, + query="SELECT id, username FROM some_table WHERE id IN (1,2)") + self.assertEqual(exp, response) def test_find_query_succeeds(self): with requests_mock.Mocker() as mock: diff --git a/make/build.mk b/make/build.mk index c2851c3a74e3fd8f56d175061f78a6cff0e8fb47..06e49be88844fac41e68c1c022c5f04877c7fe58 100644 --- a/make/build.mk +++ b/make/build.mk @@ -22,7 +22,18 @@ build-ui: ## Build the UI. build-lib: ## Build the Python Library. python3 -m build --sdist ./lib/python python3 -m build --wheel ./lib/python + cp ./lib/python/dist/dbrepo-${APP_VERSION}.tar.gz ./dbrepo-analyse-service/lib/dbrepo-${APP_VERSION}.tar.gz + (cd ./dbrepo-analyse-service && PIPENV_IGNORE_VIRTUALENVS=1 pipenv lock) + cp ./lib/python/dist/dbrepo-${APP_VERSION}.tar.gz ./dbrepo-search-service/lib/dbrepo-${APP_VERSION}.tar.gz + (cd ./dbrepo-search-service && PIPENV_IGNORE_VIRTUALENVS=1 pipenv lock) + cp ./lib/python/dist/dbrepo-${APP_VERSION}.tar.gz ./dbrepo-search-service/init/lib/dbrepo-${APP_VERSION}.tar.gz + (cd ./dbrepo-search-service/init && PIPENV_IGNORE_VIRTUALENVS=1 pipenv lock) .PHONY: build-helm -build-helm: ## Build the Helm Chart. +build-helm: ## Build the DBRepo and DBRepo MariaDB Galera Helm Charts. + ./.scripts/check-helm.sh + helm package ./helm/dbrepo-mariadb-galera --destination ./build + helm schema -input ./helm/dbrepo-mariadb-galera/values.yaml -output ./helm/dbrepo-mariadb-galera/values.schema.json + helm dependency update ./helm/dbrepo helm package ./helm/dbrepo --destination ./build + helm schema -input ./helm/dbrepo/values.yaml -output ./helm/dbrepo/values.schema.json diff --git a/make/dep.mk b/make/dep.mk deleted file mode 100644 index 25d4036cee41d8cafe49bd760a9c811a7a4ad559..0000000000000000000000000000000000000000 --- a/make/dep.mk +++ /dev/null @@ -1,9 +0,0 @@ -##@ Deployment - -.PHONY: start -start: ## Run stable deployment. - docker compose -f docker-compose.prod.yml up -d - -.PHONY: stop -stop: ## Run stable deployment. - docker compose -f docker-compose.prod.yml down diff --git a/make/dev.mk b/make/dev.mk index 2ddc6f07d083af9bae197acb2a813b04bc29c3ea..76c05989eb224c0ca0625f4d380f6467b8688f2f 100644 --- a/make/dev.mk +++ b/make/dev.mk @@ -11,12 +11,20 @@ stop-dev: ## Stop the development deployment and remove all data. .PHONY: package-config package-config: ## Package the config files + cp ./dbrepo-auth-service/dbrepo-realm.json ./.docker/config + cp ./dbrepo-auth-service/import-realms.sh ./.docker/config + cp ./dbrepo-auth-service/master-realm.json ./.docker/config cp ./dbrepo-metadata-db/1_setup-schema.sql ./.docker/config cp ./dbrepo-metadata-db/2_setup-data.sql ./.docker/config cp ./dbrepo-broker-service/rabbitmq.conf ./.docker/config cp ./dbrepo-broker-service/enabled_plugins ./.docker/config cp ./dbrepo-broker-service/definitions.json ./.docker/config cp ./dbrepo-broker-service/advanced.config ./.docker/config - cp ./dbrepo-storage-service/s3_config.json ./.docker/config + cp ./dbrepo-dashboard-service/grafana.ini ./.docker/config + cp ./dbrepo-dashboard-service/ldap.toml ./.docker/config + cp -r ./dbrepo-dashboard-service/dashboards ./.docker/config + cp -r ./dbrepo-dashboard-service/provisioning ./.docker/config cp ./dbrepo-gateway-service/dbrepo.conf ./.docker/config + cp ./dbrepo-metric-db/prometheus.yml ./.docker/config + cp ./dbrepo-storage-service/s3_config.json ./.docker/config cd ./.docker && tar czf ./dist.tar.gz ./docker-compose.yml ./.env ./config diff --git a/make/gen.mk b/make/gen.mk index b81d504213bdee6cae172d1edfc18db82f2ef65a..322bc6625941b33eb72912212f3034e6cf259dd4 100644 --- a/make/gen.mk +++ b/make/gen.mk @@ -9,7 +9,6 @@ gen-swagger-doc: build-images ## Generate Swagger documentation and fetch. .PHONY: gen-helm-doc gen-helm-doc: build-helm ## Generate Helm documentation and schema - helm schema -input ./helm/dbrepo/values.yaml -output ./helm/dbrepo/values.schema.json readme-generator-for-helm --readme ./helm/dbrepo/README.md --values ./helm/dbrepo/values.yaml .PHONY: gen-dbrepo-doc diff --git a/make/rel.mk b/make/rel.mk index 97aeca4e161ada3786dab0b3ecfca1fc2c3c5a62..042b93d5680b93115202bd207538821c952d8f28 100644 --- a/make/rel.mk +++ b/make/rel.mk @@ -4,6 +4,7 @@ tag-images: build-images ## Tag the docker images. docker tag dbrepo-analyse-service:latest "${REPOSITORY_URL}/analyse-service:${APP_VERSION}" docker tag dbrepo-auth-service:latest "${REPOSITORY_URL}/auth-service:${APP_VERSION}" + docker tag dbrepo-dashboard-service:latest "${REPOSITORY_URL}/dashboard-service:${APP_VERSION}" docker tag dbrepo-ui:latest "${REPOSITORY_URL}/ui:${APP_VERSION}" docker tag dbrepo-data-service:latest "${REPOSITORY_URL}/data-service:${APP_VERSION}" docker tag dbrepo-metadata-service:latest "${REPOSITORY_URL}/metadata-service:${APP_VERSION}" @@ -17,6 +18,7 @@ tag-images: build-images ## Tag the docker images. release-images: tag-images ## Release the docker images. docker push "${REPOSITORY_URL}/analyse-service:${APP_VERSION}" docker push "${REPOSITORY_URL}/auth-service:${APP_VERSION}" + docker push "${REPOSITORY_URL}/dashboard-service:${APP_VERSION}" docker push "${REPOSITORY_URL}/ui:${APP_VERSION}" docker push "${REPOSITORY_URL}/data-service:${APP_VERSION}" docker push "${REPOSITORY_URL}/search-db:${APP_VERSION}" @@ -25,3 +27,8 @@ release-images: tag-images ## Release the docker images. docker push "${REPOSITORY_URL}/search-service:${APP_VERSION}" docker push "${REPOSITORY_URL}/search-service-init:${APP_VERSION}" docker push "${REPOSITORY_URL}/storage-service-init:${APP_VERSION}" + +.PHONY: release-helm +release-helm: gen-helm-doc ## Release the DBRepo and DBRepo MariaDB Galera Helm charts. + helm push ./build/dbrepo-${CHART_VERSION}.tgz oci://registry.datalab.tuwien.ac.at/dbrepo/dbrepo/helm + helm push ./build/dbrepo-mariadb-galera-${CHART_VERSION}.tgz oci://registry.datalab.tuwien.ac.at/dbrepo/dbrepo/helm \ No newline at end of file diff --git a/make/test.mk b/make/test.mk index c3d2cd8804831f25d7450d0f34914c69c6f53477..36d44d42f56f1592b8cd5364efb3111617e72d30 100644 --- a/make/test.mk +++ b/make/test.mk @@ -12,6 +12,14 @@ test-metadata-service: ## Test the Metadata Service. test-analyse-service: ## Test the Analyse Service. bash ./dbrepo-analyse-service/test.sh +.PHONY: test-search-service +test-search-service: ## Test the Search Service + bash ./dbrepo-search-service/test.sh + .PHONY: test-lib test-lib: ## Test the Python Library. bash ./lib/python/test.sh + +.PHONY: test-ui +test-ui: ## Test the UI. + bash ./dbrepo-ui/test/test_heap.sh diff --git a/mkdocs.yml b/mkdocs.yml index c7481cd6e2764e9520774cf904216d92e37487e1..28f04c8365f0d0a729a0eaf093cf87ebd72ff04a 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -1,5 +1,5 @@ site_name: Database Repository -site_url: https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.4.5/ +site_url: https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.4.7/ repo_url: https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services repo_name: fda-services site_author: Research Unit Data Science, Technische Universität Wien @@ -12,11 +12,12 @@ nav: - Help with DBRepo: help.md - Installation: installation.md - Kubernetes: kubernetes.md + - changelog.md - contributing.md - Concepts: - Overview: concepts/index.md - Authentication: concepts/authentication.md - - Databases: concepts/databases.md + - Database: concepts/database.md - Messaging: concepts/messaging.md - Monitoring: concepts/monitoring.md - Persistent Identifier: concepts/pid.md @@ -27,6 +28,7 @@ nav: - Databases: - Data Database: api/data-db.md - Metadata Database: api/metadata-db.md + - Metric Database: api/metric-db.md - SDK: - Python Library: api/python.md - Swagger / OpenAPI: api/open-api.md @@ -34,6 +36,7 @@ nav: - Analyse Service: api/analyse-service.md - Auth Service: api/auth-service.md - Broker Service: api/broker-service.md + - Dashboard Service: api/dashboard-service.md - Data Service: api/data-service.md - Gateway Service: api/gateway-service.md - Identity Service: api/identity-service.md @@ -118,7 +121,7 @@ markdown_extensions: extra: homepage: https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/ version: - default: 1.4.5 + default: 1.4.7 provider: mike social: - icon: simple/artifacthub diff --git a/requirements.txt b/requirements.txt index 6442ea60759d27863ddf1879ab4e6be9151a5901..659eb487ea25bbc048959ecd8755ea65bfa84f06 100644 --- a/requirements.txt +++ b/requirements.txt @@ -14,4 +14,5 @@ requests==2.31.0 pika==1.3.2 pydantic==2.6.4 tuspy==1.0.3 -mike==2.0.0 \ No newline at end of file +mike==2.0.0 +anybadge==1.14.0 \ No newline at end of file diff --git a/sonar-project.properties b/sonar-project.properties index 45670cc4659d29f9badf6419ed16dbe2cceba60f..d034d57b104243b02aa8eb0f050a4497e39f513a 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -2,7 +2,7 @@ sonar.projectKey=fair-data-austria-db-repository_fda-services_a57fa043-ab99-4cdd-a721-162d9a916d77 sonar.host.url=https://s34.datalab.tuwien.ac.at # project -sonar.projectVersion=1.4.4 +sonar.projectVersion=1.4.7 # general sonar.qualitygate.wait=true sonar.projectCreation.mainBranchName=master diff --git a/versions.json b/versions.json index b17c2c59962f34c3f0fc4693ae0c6088212f6eb6..760242683ec68967ba967b659c87d8b970ed1cc9 100644 --- a/versions.json +++ b/versions.json @@ -1,8 +1,18 @@ [ + { + "version": "1.4.7", + "title": "1.4.7", + "aliases": [] + }, + { + "version": "1.4.6", + "title": "1.4.6", + "aliases": [] + }, { "version": "1.4.5", "title": "1.4.5", - "aliases": ["latest"] + "aliases": [] }, { "version": "1.4.4",