diff --git a/.docs/.swagger/api-data.yaml b/.docs/.swagger/api-data.yaml index 0b089a632761ddbebfcd7fe34c4a51b41d3573c5..3c8bc053922fe9e29173765b42007ac7f27f5877 100644 --- a/.docs/.swagger/api-data.yaml +++ b/.docs/.swagger/api-data.yaml @@ -14,9 +14,9 @@ externalDocs: url: https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services servers: - url: http://localhost:9093 - description: Generated server url + description: Development instance - url: https://test.dbrepo.tuwien.ac.at - description: Sandbox + description: Staging instance paths: {} components: securitySchemes: diff --git a/.docs/.swagger/api-metadata.yaml b/.docs/.swagger/api-metadata.yaml index 185142b56e223473f237db623f01f7be43eed5a3..e65ce0020b97ef9ee515d71d4e04caa94d7f659d 100644 --- a/.docs/.swagger/api-metadata.yaml +++ b/.docs/.swagger/api-metadata.yaml @@ -14,9 +14,9 @@ externalDocs: url: https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services servers: - url: http://localhost:9099 - description: Generated server url + description: Development instance - url: https://test.dbrepo.tuwien.ac.at - description: Sandbox + description: Staging instance paths: /api/database/{databaseId}/table/{tableId}/history: get: @@ -38,6 +38,18 @@ paths: type: integer format: int64 responses: + "409": + description: Query store failed to query table history + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' + "403": + description: Find table history is not permitted + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' "400": description: Table history query is malformed content: @@ -52,26 +64,15 @@ paths: type: array items: $ref: '#/components/schemas/TableHistoryDto' - "403": - description: Find table history is not permitted - content: - application/json: - schema: - $ref: '#/components/schemas/ApiErrorDto' "404": description: "Table, database or user could not be found" content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "409": - description: Query store failed to query table history - content: - application/json: - schema: - $ref: '#/components/schemas/ApiErrorDto' security: - bearerAuth: [] + - basicAuth: [] head: tags: - table-history-endpoint @@ -91,6 +92,18 @@ paths: type: integer format: int64 responses: + "409": + description: Query store failed to query table history + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' + "403": + description: Find table history is not permitted + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' "400": description: Table history query is malformed content: @@ -105,26 +118,15 @@ paths: type: array items: $ref: '#/components/schemas/TableHistoryDto' - "403": - description: Find table history is not permitted - content: - application/json: - schema: - $ref: '#/components/schemas/ApiErrorDto' "404": description: "Table, database or user could not be found" content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "409": - description: Query store failed to query table history - content: - application/json: - schema: - $ref: '#/components/schemas/ApiErrorDto' security: - bearerAuth: [] + - basicAuth: [] /api/database/{databaseId}/table/{tableId}/data: get: tags: @@ -176,20 +178,26 @@ paths: schema: type: string responses: - "422": - description: Could not import csv via sidecar + "400": + description: Table data is malformed or image is not supported content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "403": - description: Access to the database is forbidden + "404": + description: Table or database could not be found content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "400": - description: Table data is malformed or image is not supported + "422": + description: Could not import csv via sidecar + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' + "403": + description: Access to the database is forbidden content: application/json: schema: @@ -200,18 +208,14 @@ paths: '*/*': schema: $ref: '#/components/schemas/QueryResultDto' - "404": - description: Table or database could not be found - content: - application/json: - schema: - $ref: '#/components/schemas/ApiErrorDto' security: - bearerAuth: [] + - basicAuth: [] post: tags: - table-data-endpoint summary: Insert data + description: Insert data directly as key-value map tuple operationId: insert parameters: - name: databaseId @@ -233,18 +237,6 @@ paths: $ref: '#/components/schemas/TableCsvDto' required: true responses: - "202": - description: Inserted data successfully - content: - '*/*': - schema: - type: object - "403": - description: Access to the database is forbidden - content: - application/json: - schema: - $ref: '#/components/schemas/ApiErrorDto' "404": description: Table or database could not be found content: @@ -257,12 +249,26 @@ paths: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' + "202": + description: Inserted data successfully + content: + '*/*': + schema: + type: object + "403": + description: Access to the database is forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' security: - bearerAuth: [] + - basicAuth: [] delete: tags: - table-data-endpoint summary: Delete data + description: Delete a tuples that match a key-value map operationId: delete_6 parameters: - name: databaseId @@ -284,28 +290,29 @@ paths: $ref: '#/components/schemas/TableCsvDeleteDto' required: true responses: - "202": - description: Deleted table data successfully - "400": - description: Table data or query is malformed + "404": + description: Table or database could not be found content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' + "202": + description: Deleted table data successfully "403": description: Access to the database is forbidden content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "404": - description: Table or database could not be found + "400": + description: Table data or query is malformed content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' security: - bearerAuth: [] + - basicAuth: [] head: tags: - table-data-endpoint @@ -356,20 +363,26 @@ paths: schema: type: string responses: - "422": - description: Could not import csv via sidecar + "400": + description: Table data is malformed or image is not supported content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "403": - description: Access to the database is forbidden + "404": + description: Table or database could not be found content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "400": - description: Table data is malformed or image is not supported + "422": + description: Could not import csv via sidecar + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' + "403": + description: Access to the database is forbidden content: application/json: schema: @@ -380,14 +393,9 @@ paths: '*/*': schema: $ref: '#/components/schemas/QueryResultDto' - "404": - description: Table or database could not be found - content: - application/json: - schema: - $ref: '#/components/schemas/ApiErrorDto' security: - bearerAuth: [] + - basicAuth: [] /api/user/{id}: get: tags: @@ -402,12 +410,6 @@ paths: type: string format: uuid responses: - "404": - description: User was not found - content: - application/json: - schema: - $ref: '#/components/schemas/ApiErrorDto' "403": description: Find user is not permitted content: @@ -420,8 +422,15 @@ paths: application/json: schema: $ref: '#/components/schemas/UserDto' + "404": + description: User was not found + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' security: - bearerAuth: [] + - basicAuth: [] put: tags: - user-endpoint @@ -441,38 +450,39 @@ paths: $ref: '#/components/schemas/UserUpdateDto' required: true responses: - "404": - description: User attribute was not found + "400": + description: Modify user query is malformed content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "202": - description: Modified user information + "405": + description: Foreign user modification content: application/json: schema: - $ref: '#/components/schemas/UserDto' + $ref: '#/components/schemas/ApiErrorDto' "403": description: Modify user is not permitted content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "400": - description: Modify user query is malformed + "404": + description: User attribute was not found content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "405": - description: Foreign user modification + "202": + description: Modified user information content: application/json: schema: - $ref: '#/components/schemas/ApiErrorDto' + $ref: '#/components/schemas/UserDto' security: - bearerAuth: [] + - basicAuth: [] /api/user/{id}/theme: put: tags: @@ -493,32 +503,33 @@ paths: $ref: '#/components/schemas/UserThemeSetDto' required: true responses: - "403": - description: Modify user is not permitted + "405": + description: Foreign user modification content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "202": - description: Modified user theme + "403": + description: Modify user is not permitted content: application/json: schema: - $ref: '#/components/schemas/UserDto' + $ref: '#/components/schemas/ApiErrorDto' "404": description: User or user attribute was not found content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "405": - description: Foreign user modification + "202": + description: Modified user theme content: application/json: schema: - $ref: '#/components/schemas/ApiErrorDto' + $ref: '#/components/schemas/UserDto' security: - bearerAuth: [] + - basicAuth: [] /api/user/{id}/password: put: tags: @@ -539,14 +550,14 @@ paths: $ref: '#/components/schemas/UserPasswordDto' required: true responses: - "503": - description: Authentication service does not respond + "405": + description: Foreign user modification content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "404": - description: User was not found + "403": + description: Modify is not allowed content: application/json: schema: @@ -557,20 +568,21 @@ paths: application/json: schema: $ref: '#/components/schemas/UserDto' - "403": - description: Modify is not allowed + "503": + description: Authentication service does not respond content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "405": - description: Foreign user modification + "404": + description: User was not found content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' security: - bearerAuth: [] + - basicAuth: [] /api/semantic/ontology/{id}: get: tags: @@ -616,20 +628,21 @@ paths: $ref: '#/components/schemas/OntologyModifyDto' required: true responses: - "404": - description: Could not find ontology - content: - application/json: - schema: - $ref: '#/components/schemas/ApiErrorDto' "202": description: Updated ontology successfully content: application/json: schema: $ref: '#/components/schemas/OntologyDto' + "404": + description: Could not find ontology + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' security: - bearerAuth: [] + - basicAuth: [] delete: tags: - ontology-endpoint @@ -643,18 +656,19 @@ paths: type: integer format: int64 responses: + "202": + description: Deleted ontology successfully + content: + application/json: {} "404": description: Could not find ontology content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "202": - description: Deleted ontology successfully - content: - application/json: {} security: - bearerAuth: [] + - basicAuth: [] /api/maintenance/message/{id}: get: tags: @@ -700,18 +714,18 @@ paths: $ref: '#/components/schemas/BannerMessageUpdateDto' required: true responses: - "202": - description: Updated message - content: - application/json: - schema: - $ref: '#/components/schemas/BannerMessageBriefDto' "404": description: Could not find message content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' + "202": + description: Updated message + content: + application/json: + schema: + $ref: '#/components/schemas/BannerMessageBriefDto' delete: tags: - maintenance-endpoint @@ -780,20 +794,21 @@ paths: $ref: '#/components/schemas/ImageChangeDto' required: true responses: - "202": - description: Updated image successfully - content: - application/json: - schema: - $ref: '#/components/schemas/ImageDto' "404": description: Image could not be found content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' + "202": + description: Updated image successfully + content: + application/json: + schema: + $ref: '#/components/schemas/ImageDto' security: - bearerAuth: [] + - basicAuth: [] delete: tags: - image-endpoint @@ -807,16 +822,17 @@ paths: type: integer format: int64 responses: - "202": - description: Deleted image successfully "404": description: Image could not be found content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' + "202": + description: Deleted image successfully security: - bearerAuth: [] + - basicAuth: [] /api/database/{id}/visibility: put: tags: @@ -837,18 +853,18 @@ paths: $ref: '#/components/schemas/DatabaseModifyVisibilityDto' required: true responses: - "403": - description: Visibility modification is not permitted - content: - application/json: - schema: - $ref: '#/components/schemas/ApiErrorDto' "202": description: Visibility modified successfully content: application/json: schema: $ref: '#/components/schemas/DatabaseDto' + "403": + description: Visibility modification is not permitted + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' "404": description: Database could not be found content: @@ -857,6 +873,7 @@ paths: $ref: '#/components/schemas/ApiErrorDto' security: - bearerAuth: [] + - basicAuth: [] /api/database/{id}/transfer: put: tags: @@ -897,6 +914,7 @@ paths: $ref: '#/components/schemas/DatabaseDto' security: - bearerAuth: [] + - basicAuth: [] /api/database/{id}/table/{tableId}/column/{columnId}: put: tags: @@ -934,9 +952,8 @@ paths: $ref: '#/components/schemas/ColumnSemanticsUpdateDto' required: true responses: - "400": - description: Update semantic concept query is malformed or update unit of - measurement query is malformed + "404": + description: Table or database could not be found content: application/json: schema: @@ -947,20 +964,22 @@ paths: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "202": - description: Updated column semantics successfully + "400": + description: Update semantic concept query is malformed or update unit of + measurement query is malformed content: application/json: schema: - $ref: '#/components/schemas/ColumnDto' - "404": - description: Table or database could not be found + $ref: '#/components/schemas/ApiErrorDto' + "202": + description: Updated column semantics successfully content: application/json: schema: - $ref: '#/components/schemas/ApiErrorDto' + $ref: '#/components/schemas/ColumnDto' security: - bearerAuth: [] + - basicAuth: [] /api/database/{id}/access/{userId}: put: tags: @@ -987,12 +1006,6 @@ paths: $ref: '#/components/schemas/DatabaseModifyAccessDto' required: true responses: - "400": - description: Modify access query or database connection is malformed - content: - application/json: - schema: - $ref: '#/components/schemas/ApiErrorDto' "403": description: Modify access not permitted when no access is granted in the first place @@ -1006,10 +1019,17 @@ paths: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' + "400": + description: Modify access query or database connection is malformed + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' "202": description: Modify access succeeded security: - bearerAuth: [] + - basicAuth: [] post: tags: - access-endpoint @@ -1035,20 +1055,14 @@ paths: $ref: '#/components/schemas/DatabaseGiveAccessDto' required: true responses: - "403": - description: Failed giving access - content: - application/json: - schema: - $ref: '#/components/schemas/ApiErrorDto' - "202": - description: Granting access succeeded "404": description: Database or user not found content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' + "202": + description: Granting access succeeded "405": description: Granting access not permitted content: @@ -1061,8 +1075,15 @@ paths: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' + "403": + description: Failed giving access + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' security: - bearerAuth: [] + - basicAuth: [] delete: tags: - access-endpoint @@ -1094,16 +1115,17 @@ paths: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' + "202": + description: Revoked access successfully "403": description: Revoke of access not permitted as no access was found content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "202": - description: Revoked access successfully security: - bearerAuth: [] + - basicAuth: [] /api/database/{databaseId}/query/{queryId}: get: tags: @@ -1124,8 +1146,8 @@ paths: type: integer format: int64 responses: - "404": - description: "Database, query or user could not be found" + "501": + description: Image is not supported content: application/json: schema: @@ -1142,14 +1164,8 @@ paths: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "200": - description: List queries - content: - application/json: - schema: - $ref: '#/components/schemas/QueryDto' - "501": - description: Image is not supported + "404": + description: "Database, query or user could not be found" content: application/json: schema: @@ -1160,8 +1176,15 @@ paths: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' + "200": + description: List queries + content: + application/json: + schema: + $ref: '#/components/schemas/QueryDto' security: - bearerAuth: [] + - basicAuth: [] put: tags: - store-endpoint @@ -1187,14 +1210,14 @@ paths: $ref: '#/components/schemas/QueryPersistDto' required: true responses: - "400": - description: Image not supported + "200": + description: Persist query successful content: application/json: schema: - $ref: '#/components/schemas/ApiErrorDto' - "404": - description: "Database, query or user could not be found" + $ref: '#/components/schemas/QueryDto' + "405": + description: Persist query is not permitted content: application/json: schema: @@ -1205,26 +1228,27 @@ paths: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "405": - description: Persist query is not permitted + "400": + description: Image not supported content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "412": - description: Query is already persisted + "404": + description: "Database, query or user could not be found" content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "200": - description: Persist query successful + "412": + description: Query is already persisted content: application/json: schema: - $ref: '#/components/schemas/QueryDto' + $ref: '#/components/schemas/ApiErrorDto' security: - bearerAuth: [] + - basicAuth: [] /api/user: get: tags: @@ -1252,22 +1276,16 @@ paths: $ref: '#/components/schemas/SignupRequestDto' required: true responses: - "201": - description: Created user + "417": + description: User with e-mail already exists content: application/json: schema: - $ref: '#/components/schemas/UserBriefDto' + $ref: '#/components/schemas/ApiErrorDto' "400": description: Parameters are not well-formed (likely email) content: application/json: {} - "417": - description: User with e-mail already exists - content: - application/json: - schema: - $ref: '#/components/schemas/ApiErrorDto' "409": description: User with username already exists content: @@ -1280,6 +1298,12 @@ paths: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' + "201": + description: Created user + content: + application/json: + schema: + $ref: '#/components/schemas/UserBriefDto' /api/semantic/ontology: get: tags: @@ -1315,6 +1339,7 @@ paths: $ref: '#/components/schemas/OntologyDto' security: - bearerAuth: [] + - basicAuth: [] /api/maintenance/message: get: tags: @@ -1381,20 +1406,21 @@ paths: application/json: schema: $ref: '#/components/schemas/ImageDto' - "409": - description: Image already exists + "400": + description: Image specification is invalid content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "400": - description: Image specification is invalid + "409": + description: Image already exists content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' security: - bearerAuth: [] + - basicAuth: [] /api/identifier: get: tags: @@ -1457,68 +1483,69 @@ paths: $ref: '#/components/schemas/IdentifierSaveDto' required: true responses: - "502": - description: Query information could not be retrieved + "400": + description: Identifier form contains invalid request data content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "405": - description: Creating identifier not permitted + "406": + description: Creating identifier not allowed content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "204": - description: Identifier could not be created + "201": + description: Created identifier content: application/json: schema: - $ref: '#/components/schemas/ApiErrorDto' - "406": - description: Creating identifier not allowed + $ref: '#/components/schemas/IdentifierDto' + "502": + description: Query information could not be retrieved content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "400": - description: Identifier form contains invalid request data + "204": + description: Identifier could not be created content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "404": - description: "Failed to find database, table or view" + "403": + description: Insufficient access rights or authorities content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "503": - description: DataCite system did not respond + "405": + description: Creating identifier not permitted content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "409": - description: Identifier for this resource already exists + "503": + description: DataCite system did not respond content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "201": - description: Created identifier + "404": + description: "Failed to find database, table or view" content: application/json: schema: - $ref: '#/components/schemas/IdentifierDto' - "403": - description: Insufficient access rights or authorities + $ref: '#/components/schemas/ApiErrorDto' + "409": + description: Identifier for this resource already exists content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' security: - bearerAuth: [] + - basicAuth: [] /api/database: get: tags: @@ -1532,6 +1559,12 @@ paths: schema: type: string responses: + "404": + description: User not found + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' "200": description: List of databases content: @@ -1540,12 +1573,6 @@ paths: type: array items: $ref: '#/components/schemas/DatabaseBriefDto' - "404": - description: User not found - content: - application/json: - schema: - $ref: '#/components/schemas/ApiErrorDto' post: tags: - database-endpoint @@ -1558,8 +1585,9 @@ paths: $ref: '#/components/schemas/DatabaseCreateDto' required: true responses: - "503": - description: Connection to the database failed + "403": + description: Database create permission is missing or grant permissions + at broker service failed content: application/json: schema: @@ -1570,15 +1598,14 @@ paths: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "400": - description: Database create query is malformed or image is not supported + "503": + description: Connection to the database failed content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "403": - description: Database create permission is missing or grant permissions - at broker service failed + "404": + description: "Container, user or database could not be found" content: application/json: schema: @@ -1589,14 +1616,15 @@ paths: application/json: schema: $ref: '#/components/schemas/DatabaseBriefDto' - "404": - description: "Container, user or database could not be found" + "400": + description: Database create query is malformed or image is not supported content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' security: - bearerAuth: [] + - basicAuth: [] head: tags: - database-endpoint @@ -1637,6 +1665,12 @@ paths: type: integer format: int64 responses: + "404": + description: Database or user could not be found + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' "200": description: Find views successfully content: @@ -1645,14 +1679,9 @@ paths: type: array items: $ref: '#/components/schemas/ViewBriefDto' - "404": - description: Database or user could not be found - content: - application/json: - schema: - $ref: '#/components/schemas/ApiErrorDto' security: - bearerAuth: [] + - basicAuth: [] post: tags: - view-endpoint @@ -1672,8 +1701,8 @@ paths: $ref: '#/components/schemas/ViewCreateDto' required: true responses: - "403": - description: Credentials missing + "400": + description: Create view query is malformed content: application/json: schema: @@ -1690,26 +1719,26 @@ paths: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "201": - description: Create view successfully + "401": + description: Credentials missing content: application/json: schema: - $ref: '#/components/schemas/ViewBriefDto' - "503": - description: Connection to the database failed + $ref: '#/components/schemas/ApiErrorDto' + "201": + description: Create view successfully content: application/json: schema: - $ref: '#/components/schemas/ApiErrorDto' - "401": + $ref: '#/components/schemas/ViewBriefDto' + "403": description: Credentials missing content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "400": - description: Create view query is malformed + "503": + description: Connection to the database failed content: application/json: schema: @@ -1722,6 +1751,7 @@ paths: $ref: '#/components/schemas/ApiErrorDto' security: - bearerAuth: [] + - basicAuth: [] /api/database/{databaseId}/table: get: tags: @@ -1736,8 +1766,8 @@ paths: type: integer format: int64 responses: - "404": - description: Database could not be found + "403": + description: List tables not permitted content: application/json: schema: @@ -1750,14 +1780,15 @@ paths: type: array items: $ref: '#/components/schemas/TableBriefDto' - "403": - description: List tables not permitted + "404": + description: Database could not be found content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' security: - bearerAuth: [] + - basicAuth: [] post: tags: - table-endpoint @@ -1777,38 +1808,39 @@ paths: $ref: '#/components/schemas/TableCreateDto' required: true responses: - "201": - description: Created a new table + "400": + description: Create table query is malformed content: application/json: schema: - $ref: '#/components/schemas/TableBriefDto' + $ref: '#/components/schemas/ApiErrorDto' "409": description: Create table conflicts with existing table name content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "400": - description: Create table query is malformed + "201": + description: Created a new table content: application/json: schema: - $ref: '#/components/schemas/ApiErrorDto' - "404": - description: "Database, container or user could not be found" + $ref: '#/components/schemas/TableBriefDto' + "403": + description: Create table not permitted content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "403": - description: Create table not permitted + "404": + description: "Database, container or user could not be found" content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' security: - bearerAuth: [] + - basicAuth: [] /api/database/{databaseId}/table/{tableId}/data/import: post: tags: @@ -1835,34 +1867,41 @@ paths: $ref: '#/components/schemas/ImportDto' required: true responses: + "404": + description: Table or database could not be found + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' "202": description: Import table data successfully - "422": - description: Could not import csv via sidecar + "400": + description: Table data is malformed content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "403": - description: Access to the database is forbidden + "409": + description: Import failed in sidecar content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "404": - description: Table or database could not be found + "422": + description: Could not import csv via sidecar content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "400": - description: Table data is malformed + "403": + description: Access to the database is forbidden content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' security: - bearerAuth: [] + - basicAuth: [] /api/database/{databaseId}/query: get: tags: @@ -1882,16 +1921,14 @@ paths: schema: type: boolean responses: - "200": - description: List queries + "405": + description: Find all queries is not permitted content: application/json: schema: - type: array - items: - $ref: '#/components/schemas/QueryBriefDto' - "405": - description: Find all queries is not permitted + $ref: '#/components/schemas/ApiErrorDto' + "501": + description: Image is not supported content: application/json: schema: @@ -1909,12 +1946,14 @@ paths: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "501": - description: Image is not supported + "200": + description: List queries content: application/json: schema: - $ref: '#/components/schemas/ApiErrorDto' + type: array + items: + $ref: '#/components/schemas/QueryBriefDto' "504": description: Query store failed to select query content: @@ -1929,6 +1968,7 @@ paths: $ref: '#/components/schemas/ApiErrorDto' security: - bearerAuth: [] + - basicAuth: [] post: tags: - query-endpoint @@ -1973,44 +2013,45 @@ paths: $ref: '#/components/schemas/ExecuteStatementDto' required: true responses: - "404": - description: "Database, query or user could not be found" + "417": + description: Could not parse columns content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "202": - description: Executed query + "403": + description: Execute query not permitted content: application/json: schema: - $ref: '#/components/schemas/QueryResultDto' + $ref: '#/components/schemas/ApiErrorDto' "400": description: Image is not supported content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "403": - description: Execute query not permitted + "404": + description: "Database, query or user could not be found" content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "417": - description: Could not parse columns + "409": + description: Could not store query in query store content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "409": - description: Could not store query in query store + "202": + description: Executed query content: application/json: schema: - $ref: '#/components/schemas/ApiErrorDto' + $ref: '#/components/schemas/QueryResultDto' security: - bearerAuth: [] + - basicAuth: [] /api/container: get: tags: @@ -2045,6 +2086,12 @@ paths: $ref: '#/components/schemas/ContainerCreateRequestDto' required: true responses: + "409": + description: Container name already exists + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' "404": description: Container image or user could not be found content: @@ -2057,14 +2104,9 @@ paths: application/json: schema: $ref: '#/components/schemas/ContainerBriefDto' - "409": - description: Container name already exists - content: - application/json: - schema: - $ref: '#/components/schemas/ApiErrorDto' security: - bearerAuth: [] + - basicAuth: [] /api/semantic/unit: get: tags: @@ -2104,40 +2146,41 @@ paths: schema: type: string responses: - "404": - description: Could not find ontology + "200": + description: Found entities content: application/json: schema: - $ref: '#/components/schemas/ApiErrorDto' + type: array + items: + $ref: '#/components/schemas/EntityDto' "400": description: Filter params are invalid content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "200": - description: Found entities + "422": + description: Ontology does not have rdf or sparql endpoint content: application/json: schema: - type: array - items: - $ref: '#/components/schemas/EntityDto' - "417": - description: Generated query or uri is malformed + $ref: '#/components/schemas/ApiErrorDto' + "404": + description: Could not find ontology content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "422": - description: Ontology does not have rdf or sparql endpoint + "417": + description: Generated query or uri is malformed content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' security: - bearerAuth: [] + - basicAuth: [] /api/semantic/database/{databaseId}/table/{tableId}: get: tags: @@ -2158,8 +2201,8 @@ paths: type: integer format: int64 responses: - "404": - description: Could not find the table + "417": + description: Generated query is malformed content: application/json: schema: @@ -2172,8 +2215,8 @@ paths: type: array items: $ref: '#/components/schemas/TableColumnEntityDto' - "417": - description: Generated query is malformed + "404": + description: Could not find the table content: application/json: schema: @@ -2186,6 +2229,7 @@ paths: $ref: '#/components/schemas/ApiErrorDto' security: - bearerAuth: [] + - basicAuth: [] /api/semantic/database/{databaseId}/table/{tableId}/column/{columnId}: get: tags: @@ -2212,22 +2256,14 @@ paths: type: integer format: int64 responses: - "404": - description: Could not find the table column + "417": + description: Generated query is malformed content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "200": - description: Suggested table column semantics successfully - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/TableColumnEntityDto' - "417": - description: Generated query is malformed + "404": + description: Could not find the table column content: application/json: schema: @@ -2238,8 +2274,17 @@ paths: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' + "200": + description: Suggested table column semantics successfully + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/TableColumnEntityDto' security: - bearerAuth: [] + - basicAuth: [] /api/semantic/concept: get: tags: @@ -2274,6 +2319,12 @@ paths: schema: type: string responses: + "409": + description: Exported resource was not found + content: + text/csv: + schema: + $ref: '#/components/schemas/ApiErrorDto' "200": description: Found identifier successfully content: @@ -2286,29 +2337,23 @@ paths: text/bibliography; style=apa: {} text/bibliography; style=ieee: {} text/bibliography; style=bibtex: {} - "400": - description: "Identifier could not be exported, the requested style is not\ - \ known" - content: - text/bibliography: - schema: - $ref: '#/components/schemas/ApiErrorDto' - "503": - description: Identifier could not exported from database as it is not reachable + "422": + description: Failed to retrieve from database sidecar content: text/csv: schema: $ref: '#/components/schemas/ApiErrorDto' - "409": - description: Exported resource was not found + "404": + description: Identifier could not be found content: text/csv: schema: $ref: '#/components/schemas/ApiErrorDto' - "422": - description: Failed to retrieve from database sidecar + "400": + description: "Identifier could not be exported, the requested style is not\ + \ known" content: - text/csv: + text/bibliography: schema: $ref: '#/components/schemas/ApiErrorDto' "410": @@ -2317,8 +2362,8 @@ paths: text/csv: schema: $ref: '#/components/schemas/ApiErrorDto' - "404": - description: Identifier could not be found + "503": + description: Identifier could not exported from database as it is not reachable content: text/csv: schema: @@ -2390,8 +2435,8 @@ paths: type: integer format: int64 responses: - "503": - description: Connection to the broker service could not be established + "404": + description: Database or exchange could not be found content: application/json: schema: @@ -2402,14 +2447,15 @@ paths: application/json: schema: $ref: '#/components/schemas/DatabaseDto' - "404": - description: Database or exchange could not be found + "503": + description: Connection to the broker service could not be established content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' security: - bearerAuth: [] + - basicAuth: [] /api/database/{id}/table/{tableId}/export: get: tags: @@ -2436,8 +2482,14 @@ paths: type: string format: date-time responses: - "404": - description: "Table, database or user was not found" + "201": + description: Created identifier + content: + application/json: + schema: + $ref: '#/components/schemas/IdentifierDto' + "403": + description: Operation is not allowed content: application/json: schema: @@ -2448,38 +2500,39 @@ paths: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "422": - description: Sidecar operation could not be completed + "400": + description: Images is not supported or table/query is malformed content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "403": - description: Operation is not allowed + "404": + description: "Table, database or user was not found" content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "400": - description: Images is not supported or table/query is malformed + "410": + description: Blob storage operation could not be completed content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "410": - description: Blob storage operation could not be completed + "409": + description: Failed to export file from sidecar content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "201": - description: Created identifier + "422": + description: Sidecar operation could not be completed content: application/json: schema: - $ref: '#/components/schemas/IdentifierDto' + $ref: '#/components/schemas/ApiErrorDto' security: - bearerAuth: [] + - basicAuth: [] /api/database/{id}/access: get: tags: @@ -2494,6 +2547,12 @@ paths: type: integer format: int64 responses: + "404": + description: Database not found + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' "200": description: Found database access content: @@ -2506,14 +2565,9 @@ paths: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "404": - description: Database not found - content: - application/json: - schema: - $ref: '#/components/schemas/ApiErrorDto' security: - bearerAuth: [] + - basicAuth: [] /api/database/{databaseId}/view/{viewId}: get: tags: @@ -2534,18 +2588,18 @@ paths: type: integer format: int64 responses: - "200": - description: Find view successfully - content: - application/json: - schema: - $ref: '#/components/schemas/ViewDto' "403": description: Find view is not permitted content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' + "200": + description: Find view successfully + content: + application/json: + schema: + $ref: '#/components/schemas/ViewDto' "404": description: "Database, view or user could not be found" content: @@ -2554,6 +2608,7 @@ paths: $ref: '#/components/schemas/ApiErrorDto' security: - bearerAuth: [] + - basicAuth: [] delete: tags: - view-endpoint @@ -2573,8 +2628,10 @@ paths: type: integer format: int64 responses: - "403": - description: Deletion not allowed + "200": + description: Delete view successfully + "405": + description: Delete view is not permitted content: application/json: schema: @@ -2585,14 +2642,14 @@ paths: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "405": - description: Delete view is not permitted + "403": + description: Deletion not allowed content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "404": - description: "Database, view or user could not be found" + "400": + description: Delete view query is malformed content: application/json: schema: @@ -2603,16 +2660,15 @@ paths: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "400": - description: Delete view query is malformed + "404": + description: "Database, view or user could not be found" content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "200": - description: Delete view successfully security: - bearerAuth: [] + - basicAuth: [] /api/database/{databaseId}/view/{viewId}/data: get: tags: @@ -2645,14 +2701,14 @@ paths: type: integer format: int64 responses: - "403": - description: View data not allowed + "200": + description: Find data successfully content: application/json: schema: - $ref: '#/components/schemas/ApiErrorDto' - "404": - description: "Database, view, container or user could not be found" + $ref: '#/components/schemas/QueryResultDto' + "403": + description: View data not allowed content: application/json: schema: @@ -2663,14 +2719,15 @@ paths: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "200": - description: Find data successfully + "404": + description: "Database, view, container or user could not be found" content: application/json: schema: - $ref: '#/components/schemas/QueryResultDto' + $ref: '#/components/schemas/ApiErrorDto' security: - bearerAuth: [] + - basicAuth: [] /api/database/{databaseId}/view/{viewId}/data/count: get: tags: @@ -2691,39 +2748,40 @@ paths: type: integer format: int64 responses: - "404": - description: "Database, view, container or user could not be found" - content: - application/json: - schema: - $ref: '#/components/schemas/ApiErrorDto' - "400": - description: Pagination not in valid range or find data query is malformed + "200": + description: Count data successfully content: application/json: schema: - $ref: '#/components/schemas/ApiErrorDto' + type: integer + format: int64 "403": description: Count data not allowed content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "200": - description: Count data successfully + "400": + description: Pagination not in valid range or find data query is malformed content: application/json: schema: - type: integer - format: int64 + $ref: '#/components/schemas/ApiErrorDto' "409": description: Could not count query data content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' + "404": + description: "Database, view, container or user could not be found" + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' security: - bearerAuth: [] + - basicAuth: [] /api/database/{databaseId}/table/{tableId}: get: tags: @@ -2744,8 +2802,8 @@ paths: type: integer format: int64 responses: - "403": - description: Access to the database is forbidden + "503": + description: Could not communicate with the broker service content: application/json: schema: @@ -2762,14 +2820,15 @@ paths: application/json: schema: $ref: '#/components/schemas/TableDto' - "503": - description: Could not communicate with the broker service + "403": + description: Access to the database is forbidden content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' security: - bearerAuth: [] + - basicAuth: [] delete: tags: - table-endpoint @@ -2791,8 +2850,8 @@ paths: responses: "202": description: Delete table successfully - "403": - description: Access to the database is forbidden + "400": + description: Delete table query resulted in an invalid query statement content: application/json: schema: @@ -2803,14 +2862,15 @@ paths: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "400": - description: Delete table query resulted in an invalid query statement + "403": + description: Access to the database is forbidden content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' security: - bearerAuth: [] + - basicAuth: [] /api/database/{databaseId}/table/{tableId}/data/count: get: tags: @@ -2837,26 +2897,26 @@ paths: type: string format: date-time responses: - "422": - description: Could not import csv via sidecar + "400": + description: Table data is malformed or image is not supported content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "403": - description: Access to the database is forbidden + "404": + description: Table or database could not be found content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "400": - description: Table data is malformed or image is not supported + "422": + description: Could not import csv via sidecar content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "404": - description: Table or database could not be found + "403": + description: Access to the database is forbidden content: application/json: schema: @@ -2870,6 +2930,7 @@ paths: format: int64 security: - bearerAuth: [] + - basicAuth: [] /api/database/{databaseId}/query/{queryId}/export: get: tags: @@ -2895,8 +2956,8 @@ paths: schema: type: string responses: - "404": - description: Database or query could not be found + "409": + description: Export of query failed content: application/json: schema: @@ -2907,20 +2968,14 @@ paths: '*/*': schema: type: object - "400": - description: Image is not supported - content: - application/json: - schema: - $ref: '#/components/schemas/ApiErrorDto' "403": description: Execute query not permitted content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "422": - description: Sidecar failed to export + "400": + description: Image is not supported content: application/json: schema: @@ -2931,14 +2986,21 @@ paths: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "409": - description: Export of query failed + "422": + description: Sidecar failed to export + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' + "404": + description: Database or query could not be found content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' security: - bearerAuth: [] + - basicAuth: [] /api/database/{databaseId}/query/{queryId}/data: get: tags: @@ -2984,44 +3046,45 @@ paths: schema: type: string responses: - "404": - description: Database or query could not be found + "417": + description: Could not parse columns content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "202": - description: Executed query + "403": + description: Execute query not permitted content: application/json: schema: - $ref: '#/components/schemas/QueryResultDto' + $ref: '#/components/schemas/ApiErrorDto' "400": description: Image is not supported content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "403": - description: Execute query not permitted + "409": + description: Could not store query in query store content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "417": - description: Could not parse columns + "202": + description: Executed query content: application/json: schema: - $ref: '#/components/schemas/ApiErrorDto' - "409": - description: Could not store query in query store + $ref: '#/components/schemas/QueryResultDto' + "404": + description: Database or query could not be found content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' security: - bearerAuth: [] + - basicAuth: [] /api/database/{databaseId}/query/{queryId}/data/count: get: tags: @@ -3042,38 +3105,39 @@ paths: type: integer format: int64 responses: - "404": - description: Database or query could not be found + "417": + description: Could not parse columns content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "202": - description: Executed query + "403": + description: Execute query not permitted content: application/json: schema: - $ref: '#/components/schemas/QueryResultDto' + $ref: '#/components/schemas/ApiErrorDto' "400": description: Image is not supported content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "403": - description: Execute query not permitted + "202": + description: Executed query content: application/json: schema: - $ref: '#/components/schemas/ApiErrorDto' - "417": - description: Could not parse columns + $ref: '#/components/schemas/QueryResultDto' + "404": + description: Database or query could not be found content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' security: - bearerAuth: [] + - basicAuth: [] /api/database/license: get: tags: @@ -3103,18 +3167,18 @@ paths: type: integer format: int64 responses: - "200": - description: Found container - content: - application/json: - schema: - $ref: '#/components/schemas/ContainerDto' "404": description: Container image could not be found content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' + "200": + description: Found container + content: + application/json: + schema: + $ref: '#/components/schemas/ContainerDto' delete: tags: - container-endpoint @@ -3128,20 +3192,21 @@ paths: type: integer format: int64 responses: - "404": - description: Container not found - content: - application/json: - schema: - $ref: '#/components/schemas/ApiErrorDto' "202": description: Deleted container successfully content: '*/*': schema: type: object + "404": + description: Container not found + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' security: - bearerAuth: [] + - basicAuth: [] /api/pid/{id}: delete: tags: @@ -3156,14 +3221,14 @@ paths: type: integer format: int64 responses: - "404": - description: Identifier or database could not be found + "403": + description: Deleting identifier not permitted content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "403": - description: Deleting identifier not permitted + "404": + description: Identifier or database could not be found content: application/json: schema: @@ -3176,6 +3241,7 @@ paths: type: object security: - bearerAuth: [] + - basicAuth: [] components: schemas: ApiErrorDto: @@ -3332,6 +3398,9 @@ components: affiliation: type: string example: Brown University + theme_dark: + type: boolean + example: false UserDto: required: - attributes @@ -4998,6 +5067,25 @@ components: is_public: type: boolean example: true + num_rows: + type: integer + format: int64 + example: 5 + data_length: + type: integer + description: in bytes + format: int64 + example: 16384 + max_data_length: + type: integer + description: in bytes + format: int64 + example: 0 + avg_row_length: + type: integer + description: in bytes + format: int64 + example: 3276 UniqueDto: required: - columns @@ -6644,10 +6732,10 @@ components: type: string parametersString: type: string - fromDate: + untilDate: type: string format: date-time - untilDate: + fromDate: type: string format: date-time BannerMessageDto: @@ -8109,6 +8197,9 @@ components: additionalProperties: type: object securitySchemes: + basicAuth: + type: http + scheme: basic bearerAuth: type: http scheme: bearer diff --git a/.docs/.swagger/custom.css b/.docs/.swagger/custom.css new file mode 100644 index 0000000000000000000000000000000000000000..b4eb2af41ecae38ea62d2a693853ee79905985b8 --- /dev/null +++ b/.docs/.swagger/custom.css @@ -0,0 +1,10 @@ +html, +body { + background: #eee; +} + +.scheme-container { + background: none !important; + box-shadow: none !important; + padding: 0 !important; +} \ No newline at end of file diff --git a/.docs/.swagger/dist.tar.gz b/.docs/.swagger/dist.tar.gz deleted file mode 100644 index c23425955d630805b73530bf20cad4c28369bcb1..0000000000000000000000000000000000000000 Binary files a/.docs/.swagger/dist.tar.gz and /dev/null differ diff --git a/.docs/.swagger/swagger-site.sh b/.docs/.swagger/swagger-site.sh index 98b8056a7773ac0288b3a6f7eaede10444ad0836..b9a0d163e9649e1766a2efed232ea634a45c5916 100644 --- a/.docs/.swagger/swagger-site.sh +++ b/.docs/.swagger/swagger-site.sh @@ -8,8 +8,8 @@ services[9099]=metadata services[3305]=sidecar # clean up -echo "clean up ./dist ./site" -rm -rf ./dist ./site +echo "clean up ./site" +rm -rf ./site # ensure target directories are present echo "ensure target directory ./site are present" @@ -17,11 +17,11 @@ mkdir -p ./site # extract static site echo "extract static site .docs/.swagger/dist.tar.gz" -tar xzf .docs/.swagger/dist.tar.gz for key in "${!services[@]}"; do mkdir -p ./site/${services[$key]} - echo "extract static site ./dist -> ./site/${services[$key]}" - cp -r ./dist/* ./site/${services[$key]} - echo "placing .docs/.swagger/api-${services[$key]}.yaml -> ./site/${services[$key]}/api.yaml" + echo "extract static site ./swagger-ui.html -> ./site/${services[$key]}" + cp .docs/.swagger/swagger-ui.html ./site/${services[$key]}/index.html + cp .docs/.swagger/custom.css ./site/${services[$key]}/custom.css + sed -i -e "s/__SERVICENAME__/${services[$key]^} Service/g" ./site/${services[$key]}/index.html cp ".docs/.swagger/api-${services[$key]}.yaml" "./site/${services[$key]}/api.yaml" done \ No newline at end of file diff --git a/.docs/.swagger/swagger-ui.html b/.docs/.swagger/swagger-ui.html new file mode 100644 index 0000000000000000000000000000000000000000..ef3ce5574300058bb87b6b7d5c2dbbb56c9255d3 --- /dev/null +++ b/.docs/.swagger/swagger-ui.html @@ -0,0 +1,25 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="utf-8"/> + <meta name="viewport" content="width=device-width, initial-scale=1"/> + <meta name="description" content="__SERVICENAME__ API description in OpenAPI 3.0"/> + <title>__SERVICENAME__ API</title> + <link rel="stylesheet" href="https://unpkg.com/swagger-ui-dist@5.11.1/swagger-ui.css"/> + <link rel="stylesheet" href="./custom.css"/> + <link rel="icon" href="https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/raw/master/.docs/images/signet_white.png" /> +</head> +<body> +<div id="swagger-ui"></div> +<script src="https://unpkg.com/swagger-ui-dist@5.11.1/swagger-ui-bundle.js" crossorigin></script> +<script src="https://unpkg.com/swagger-ui-dist@5.11.1/swagger-ui-standalone-preset.js" crossorigin></script> +<script> + window.onload = () => { + window.ui = SwaggerUIBundle({ + url: 'api.yaml', + dom_id: '#swagger-ui', + }); + }; +</script> +</body> +</html> \ No newline at end of file diff --git a/.docs/deployment-helm.md b/.docs/deployment-helm.md index 70372724aab70877e3ddebc416085fd07cde5d0f..17d54e79d3d9dc2d0740df4b9c0ccc3f1c81148e 100644 --- a/.docs/deployment-helm.md +++ b/.docs/deployment-helm.md @@ -29,7 +29,7 @@ about values, etc. ## 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](../system-databases-auth). + only a single MariaDB pod can be deployed at once for the [auth database](../system-databases-authentication). !!! question "Do you miss functionality? Do these limitations affect you?" diff --git a/.docs/images/architecture.drawio b/.docs/images/architecture.drawio index f493f476b2e933ed3c1fc5d78ef864dd629ae9b2..430288776b59c34f9274af800c42a0c6fc3d3f44 100644 --- a/.docs/images/architecture.drawio +++ b/.docs/images/architecture.drawio @@ -1,4 +1,4 @@ -<mxfile host="Electron" modified="2024-01-18T09:36:17.787Z" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/22.1.18 Chrome/120.0.6099.199 Electron/28.1.2 Safari/537.36" etag="VyIG_SLmjDzwPbzvCqrk" version="22.1.18" type="device" pages="7"> +<mxfile host="Electron" modified="2024-01-27T20:29:22.079Z" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/23.0.2 Chrome/120.0.6099.109 Electron/28.1.0 Safari/537.36" etag="yip1JA4z9fltPW3TVpkZ" version="23.0.2" type="device" pages="7"> <diagram id="mvBsv1rP8O80Qe3yGnn_" name="docker-compose"> <mxGraphModel dx="1434" dy="822" 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> @@ -581,8 +581,8 @@ </root> </mxGraphModel> </diagram> - <diagram id="e2fuorb2m_XjboQ7R7_y" name="Data Ingest"> - <mxGraphModel dx="1147" dy="658" 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"> + <diagram id="e2fuorb2m_XjboQ7R7_y" name="data-ingest"> + <mxGraphModel dx="1195" dy="685" 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" /> @@ -600,21 +600,6 @@ <mxPoint as="offset" /> </mxGeometry> </mxCell> - <mxCell id="0VJCIkSjTVNNat6pGbHc-35" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.75;exitY=1;exitDx=0;exitDy=0;entryX=0;entryY=0;entryDx=0;entryDy=27.5;entryPerimeter=0;" parent="1" source="0VJCIkSjTVNNat6pGbHc-3" edge="1"> - <mxGeometry relative="1" as="geometry"> - <Array as="points"> - <mxPoint x="480" y="340" /> - <mxPoint x="530" y="340" /> - <mxPoint x="530" y="428" /> - </Array> - <mxPoint x="575" y="427.5" as="targetPoint" /> - </mxGeometry> - </mxCell> - <mxCell id="0VJCIkSjTVNNat6pGbHc-36" value="3306/tcp" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="0VJCIkSjTVNNat6pGbHc-35" vertex="1" connectable="0"> - <mxGeometry x="0.2112" y="-1" relative="1" as="geometry"> - <mxPoint as="offset" /> - </mxGeometry> - </mxCell> <mxCell id="0VJCIkSjTVNNat6pGbHc-41" 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;" parent="1" source="0VJCIkSjTVNNat6pGbHc-3" target="0VJCIkSjTVNNat6pGbHc-33" edge="1"> <mxGeometry relative="1" as="geometry"> <mxPoint x="395" y="318" as="sourcePoint" /> @@ -648,8 +633,8 @@ <mxCell id="0VJCIkSjTVNNat6pGbHc-7" value="<b>JDBC</b>" style="shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;outlineConnect=0;" parent="1" vertex="1"> <mxGeometry x="584" y="170" width="30" height="60" as="geometry" /> </mxCell> - <mxCell id="0VJCIkSjTVNNat6pGbHc-8" value="3306/tcp" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#000000;startArrow=classic;startFill=1;dashed=1;" parent="1" edge="1"> - <mxGeometry x="-0.314" relative="1" as="geometry"> + <mxCell id="0VJCIkSjTVNNat6pGbHc-8" value="3307/tcp" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#000000;startArrow=classic;startFill=1;dashed=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;exitPerimeter=0;" parent="1" edge="1" source="yvNGLmbJRMNvVS071MuP-1"> + <mxGeometry x="-0.0158" relative="1" as="geometry"> <mxPoint x="513" y="300" as="sourcePoint" /> <mxPoint as="offset" /> <mxPoint x="600" y="250" as="targetPoint" /> @@ -675,7 +660,7 @@ </mxCell> <mxCell id="0VJCIkSjTVNNat6pGbHc-38" value="3306/tcp" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="0VJCIkSjTVNNat6pGbHc-37" vertex="1" connectable="0"> <mxGeometry x="-0.1716" y="1" relative="1" as="geometry"> - <mxPoint as="offset" /> + <mxPoint x="3" y="-8" as="offset" /> </mxGeometry> </mxCell> <mxCell id="0VJCIkSjTVNNat6pGbHc-26" value="Data Service<br>(Spring AMQP)" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1"> @@ -687,18 +672,13 @@ <mxCell id="0VJCIkSjTVNNat6pGbHc-29" value="Broker Service<br style="border-color: var(--border-color);">(RabbitMQ)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#E6E6E6;" parent="1" vertex="1"> <mxGeometry x="399.5" y="360" width="96" height="40" as="geometry" /> </mxCell> - <mxCell id="0VJCIkSjTVNNat6pGbHc-39" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0;entryDx=0;entryDy=52.5;entryPerimeter=0;" parent="1" source="0VJCIkSjTVNNat6pGbHc-33" edge="1"> + <mxCell id="0VJCIkSjTVNNat6pGbHc-39" 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;" parent="1" source="0VJCIkSjTVNNat6pGbHc-33" edge="1" target="yvNGLmbJRMNvVS071MuP-1"> <mxGeometry relative="1" as="geometry"> <Array as="points"> <mxPoint x="530" y="500" /> - <mxPoint x="530" y="453" /> + <mxPoint x="530" y="440" /> </Array> - <mxPoint x="575" y="452.5" as="targetPoint" /> - </mxGeometry> - </mxCell> - <mxCell id="0VJCIkSjTVNNat6pGbHc-40" value="3306/tcp" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="0VJCIkSjTVNNat6pGbHc-39" vertex="1" connectable="0"> - <mxGeometry x="-0.0808" y="-1" relative="1" as="geometry"> - <mxPoint x="-29" y="-1" as="offset" /> + <mxPoint x="570" y="440" as="targetPoint" /> </mxGeometry> </mxCell> <mxCell id="0VJCIkSjTVNNat6pGbHc-33" value="Metadata Service<br>(Spring AMQP)" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1"> @@ -710,25 +690,25 @@ <mxCell id="JkB3rZmVi6YrdEwAjtGV-5" value="Storage Service<br>(SeaweedFS)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#E6E6E6;" parent="1" vertex="1"> <mxGeometry x="237" y="394" width="96" height="40" as="geometry" /> </mxCell> - <mxCell id="yvNGLmbJRMNvVS071MuP-1" value="" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=8.600000000000023;fillColor=#dae8fc;strokeColor=#000000;" vertex="1" parent="1"> + <mxCell id="yvNGLmbJRMNvVS071MuP-1" value="" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=8.600000000000023;fillColor=#dae8fc;strokeColor=#000000;" parent="1" vertex="1"> <mxGeometry x="575" y="408" width="50" height="64" as="geometry" /> </mxCell> - <mxCell id="yvNGLmbJRMNvVS071MuP-2" value="data-db" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;spacing=-1;" vertex="1" parent="1"> + <mxCell id="yvNGLmbJRMNvVS071MuP-2" 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="559" y="470" width="85" height="20" as="geometry" /> </mxCell> - <mxCell id="jJosZR_OhRTGx9p3jnjP-1" value="" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#E6E6E6;" vertex="1" parent="1"> + <mxCell id="jJosZR_OhRTGx9p3jnjP-1" value="" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#E6E6E6;" parent="1" vertex="1"> <mxGeometry x="447.5" y="540" width="30" height="16" as="geometry" /> </mxCell> - <mxCell id="jJosZR_OhRTGx9p3jnjP-2" value="External images" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1"> + <mxCell id="jJosZR_OhRTGx9p3jnjP-2" value="External images" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1"> <mxGeometry x="485" y="540" width="140" height="16" as="geometry" /> </mxCell> - <mxCell id="jJosZR_OhRTGx9p3jnjP-3" value="" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1"> + <mxCell id="jJosZR_OhRTGx9p3jnjP-3" value="" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1"> <mxGeometry x="447.5" y="560" width="30" height="16" as="geometry" /> </mxCell> - <mxCell id="jJosZR_OhRTGx9p3jnjP-4" value="Maintained images" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1"> + <mxCell id="jJosZR_OhRTGx9p3jnjP-4" value="Maintained images" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1"> <mxGeometry x="485" y="560" width="140" height="16" as="geometry" /> </mxCell> - <mxCell id="jJosZR_OhRTGx9p3jnjP-5" value="" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#000000;" vertex="1" parent="1"> + <mxCell id="jJosZR_OhRTGx9p3jnjP-5" value="" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#000000;" parent="1" vertex="1"> <mxGeometry x="462.5" y="540" width="15" height="16" as="geometry" /> </mxCell> </root> diff --git a/.docs/images/data-ingest.svg b/.docs/images/data-ingest.svg index 7d2d1c383092ca7be8be502a74d8f1df3c09f920..20dac76c850b583c00933cffc712aa1158fc2898 100644 --- a/.docs/images/data-ingest.svg +++ b/.docs/images/data-ingest.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="408px" height="440px" viewBox="-0.5 -0.5 408 440"><defs/><g><path d="M 211 83 L 211.52 112.52 L 210.48 112.52 L 210.5 134.63" fill="none" stroke="#000000" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/><path d="M 210.5 139.88 L 206.99 132.88 L 210.5 134.63 L 213.99 132.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><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: 112px; margin-left: 212px;"><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;">5672/tcp</div></div></div></foreignObject><text x="212" y="115" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">5672/tcp</text></switch></g><ellipse cx="210.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 210.5 15 L 210.5 40 M 210.5 20 L 195.5 20 M 210.5 20 L 225.5 20 M 210.5 40 L 195.5 60 M 210.5 40 L 225.5 60" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><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: 211px;"><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;"><b>AMQP</b></div></div></div></foreignObject><text x="211" y="79" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">AMQP</text></switch></g><path d="M 210.5 181 L 210.5 216.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 210.5 221.88 L 207 214.88 L 210.5 216.63 L 214 214.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><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: 210px;"><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;">5672/tcp</div></div></div></foreignObject><text x="210" y="201" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">5672/tcp</text></switch></g><path d="M 243 181 L 243.04 203 L 293.04 203 L 293.04 290.52 L 331.63 290.5" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 336.88 290.5 L 329.88 294 L 331.63 290.5 L 329.88 287 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><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: 255px; margin-left: 292px;"><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;">3306/tcp</div></div></div></foreignObject><text x="292" y="259" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">3306/tcp</text></switch></g><path d="M 178 181 L 178 203 L 127.04 203 L 127 336.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 127 341.88 L 123.5 334.88 L 127 336.63 L 130.5 334.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><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: 250px; margin-left: 126px;"><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;">80/tcp</div></div></div></foreignObject><text x="126" y="254" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">80/tcp</text></switch></g><path d="M 178 181 L 178 203 L 48 203 L 48 250.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 48 255.88 L 44.5 248.88 L 48 250.63 L 51.5 248.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><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: 220px; margin-left: 46px;"><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;">9000/tcp</div></div></div></foreignObject><text x="46" y="224" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">9000/tcp</text></switch></g><rect x="145.5" y="141" width="130" height="40" rx="6" ry="6" fill="#e6e6e6" stroke="rgb(0, 0, 0)" pointer-events="all"/><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: 161px; margin-left: 147px;"><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;">Gateway Service<br style="border-color: var(--border-color);" />(NGINX)</div></div></div></foreignObject><text x="211" y="165" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Gateway Service...</text></switch></g><ellipse cx="362" cy="40.5" rx="7.5" ry="7.5" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><path d="M 362 48 L 362 73 M 362 53 L 347 53 M 362 53 L 377 53 M 362 73 L 347 93 M 362 73 L 377 93" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><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: 100px; margin-left: 362px;"><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;"><b>JDBC</b></div></div></div></foreignObject><text x="362" y="112" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">JDBC</text></switch></g><path d="M 282.37 163.03 L 363.52 163.48 L 363.07 119.37" fill="none" stroke="#000000" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/><path d="M 277.12 163.01 L 284.14 159.54 L 282.37 163.03 L 284.1 166.54 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 363.01 114.12 L 366.58 121.08 L 363.07 119.37 L 359.58 121.15 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><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: 163px; margin-left: 323px;"><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;">3306/tcp</div></div></div></foreignObject><text x="323" y="167" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">3306/tcp</text></switch></g><ellipse cx="58" cy="40.5" rx="7.5" ry="7.5" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><path d="M 58 48 L 58 73 M 58 53 L 43 53 M 58 53 L 73 53 M 58 73 L 43 93 M 58 73 L 73 93" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><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: 100px; margin-left: 58px;"><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;"><b>API</b></div></div></div></foreignObject><text x="58" y="112" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">API</text></switch></g><path d="M 58 119.37 L 58 163 L 139.63 163" fill="none" stroke="#000000" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/><path d="M 58 114.12 L 61.5 121.12 L 58 119.37 L 54.5 121.12 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 144.88 163 L 137.88 166.5 L 139.63 163 L 137.88 159.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><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: 163px; margin-left: 93px;"><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;">80/tcp</div></div></div></foreignObject><text x="93" y="166" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">80/tcp</text></switch></g><path d="M 258.5 303 L 298.24 303 L 331.63 303" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 336.88 303 L 329.88 306.5 L 331.63 303 L 329.88 299.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><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: 302px; margin-left: 292px;"><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;">3306/tcp</div></div></div></foreignObject><text x="292" y="306" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">3306/tcp</text></switch></g><rect x="162.5" y="283" width="96" height="40" rx="6" ry="6" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><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: 94px; height: 1px; padding-top: 303px; margin-left: 164px;"><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<br />(Spring AMQP)</div></div></div></foreignObject><text x="211" y="307" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Data Service...</text></switch></g><path d="M 210.5 263 L 210.5 276.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 210.5 281.88 L 207 274.88 L 210.5 276.63 L 214 274.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><rect x="162.5" y="223" width="96" height="40" rx="6" ry="6" fill="#e6e6e6" stroke="rgb(0, 0, 0)" pointer-events="all"/><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: 94px; height: 1px; padding-top: 243px; margin-left: 164px;"><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<br style="border-color: var(--border-color);" />(RabbitMQ)</div></div></div></foreignObject><text x="211" y="247" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Broker Service...</text></switch></g><path d="M 175 363 L 293.04 363 L 293.04 315.48 L 331.63 315.5" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 336.88 315.5 L 329.88 319 L 331.63 315.5 L 329.88 312 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><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: 363px; margin-left: 243px;"><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;">3306/tcp</div></div></div></foreignObject><text x="243" y="367" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">3306/tcp</text></switch></g><rect x="79" y="343" width="96" height="40" rx="6" ry="6" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><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: 94px; height: 1px; padding-top: 363px; margin-left: 80px;"><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<br />(Spring AMQP)</div></div></div></foreignObject><text x="127" y="367" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Metadata Service...</text></switch></g><path d="M 48 297 L 48 363 L 72.63 363" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 77.88 363 L 70.88 366.5 L 72.63 363 L 70.88 359.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><rect x="0" y="257" width="96" height="40" rx="6" ry="6" fill="#e6e6e6" stroke="rgb(0, 0, 0)" pointer-events="all"/><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: 94px; height: 1px; padding-top: 277px; margin-left: 1px;"><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;">Storage Service<br />(SeaweedFS)</div></div></div></foreignObject><text x="48" y="281" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Storage Service...</text></switch></g><path d="M 338 279.6 C 338 274.85 349.19 271 363 271 C 369.63 271 375.99 271.91 380.68 273.52 C 385.37 275.13 388 277.32 388 279.6 L 388 326.4 C 388 331.15 376.81 335 363 335 C 349.19 335 338 331.15 338 326.4 Z" fill="#dae8fc" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 388 279.6 C 388 284.35 376.81 288.2 363 288.2 C 349.19 288.2 338 284.35 338 279.6" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><rect x="322" y="333" width="85" height="20" fill="none" stroke="none" pointer-events="all"/><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: 343px; margin-left: 320px;"><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><text x="365" y="347" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">data-db</text></switch></g><rect x="210.5" y="403" width="30" height="16" fill="#e6e6e6" stroke="rgb(0, 0, 0)" pointer-events="all"/><rect x="248" y="403" width="140" height="16" fill="none" stroke="none" pointer-events="all"/><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: 138px; height: 1px; padding-top: 411px; margin-left: 250px;"><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;">External images</div></div></div></foreignObject><text x="250" y="415" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px">External images</text></switch></g><rect x="210.5" y="423" width="30" height="16" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><rect x="248" y="423" width="140" height="16" fill="none" stroke="none" pointer-events="all"/><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: 138px; height: 1px; padding-top: 431px; margin-left: 250px;"><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><text x="250" y="435" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px">Maintained images</text></switch></g><rect x="225.5" y="403" width="15" height="16" fill="#dae8fc" stroke="#000000" pointer-events="all"/></g><switch><g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/><a transform="translate(0,-5)" xlink:href="https://www.drawio.com/doc/faq/svg-export-text-problems" target="_blank"><text text-anchor="middle" font-size="10px" x="50%" y="100%">Text is not SVG - cannot display</text></a></switch></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="408px" height="441px" viewBox="-0.5 -0.5 408 441" style="background-color: rgb(255, 255, 255);"><defs/><rect fill="#ffffff" width="100%" height="100%" x="0" y="0"/><g><path d="M 211 83 L 211.5 112.5 L 210.5 112.5 L 210.5 134.63" fill="none" stroke="#000000" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/><path d="M 210.5 139.88 L 207 132.88 L 210.5 134.63 L 214 132.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><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: 111px; margin-left: 211px;"><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;">5672/tcp</div></div></div></foreignObject><image x="190" y="105" width="42" height="18.5" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKgAAABKCAYAAAAvxx89AAAAAXNSR0IArs4c6QAAEXVJREFUeF7tnGO0JEkThmPWtm3bnp21bdu2OWvbtm3btm3bO3ue/L6ojc6pqszq27P3VnfGOfNjbmUl3wy8EdW9+vXr10+SpB3ooTvQKwG0h55MmpbbgQTQBIQevQMJoD36eNLkEkATBnr0DiSA9ujjSZNLAE0Y6NE7kADao48nTS4BtCYYuPbaa2X55Zf/H/XSq5d8+umnMtpoo9Vk9s1PswGg5557rqy//vrN9yYiE088sbz55puV+nj22WflggsukPvuu8+9++OPP8rQQw8tY401lsw888yy0korydJLLy0DDzxwab/zzz+/66NVcscdd8hCCy0U7O7++++Xq666Sh555BF5//335ZtvvpFBBx1URhxxRJlssslkjjnmkDXWWEOmnnrqYF9FDbbYYgs55ZRT3OMZZphBnnnmmab7qtOLDQA99thjZfvtt+/S/KsA9MsvvxQ2/oorrgiOOc0008g555wjs8wyS2Hb/xqgTz31lGyyySby9NNPB+dPgyWXXFJOP/10d/GqCvv69ttvu9d22WUXOeyww6p2Ucv2DQDdb7/9ZP/99+/SQmIBymYvuOCC8u6770aPN9RQQ8nNN98svXv3zn3nvwToeeedJxtttJH8+eef0fOn4SijjCJo3CmnnDL6vbfeeksmmWSSrP2dd97p9s7KwQcfLHvuuaf7E5ocrd0O0gDQ7bbbTo477rhsXccff7yMOeaYldY5zDDDyGKLLVb6znfffedMNxuvMvzww8u6664rffr0kTHGGEM++eQTefTRR+XUU0+V77//Pms36qijyssvv+wO2hfM+xdffFFpvrbxoYceKmhFZNhhh5VXX301V9tdd911ssIKK8jff/+dvc7lWX311d382bPffvtNXnvtNbnyyivloYceapjT+OOPLy+99JJzY2Lk5JNPli233NI1ZZyvv/5aBh988IZXl1pqKbnpppvaG6DrrbeeoBlUPv7448oAjdnwjTfeWM4888ys6WyzzSZXX321jD322P29/vnnnwua8ZVXXsmecZGOOeaYmKGi26DVGEdrZ7io22yzTX/vf/vttzLFFFPIZ599lj1DW+GmjDPOOLnjnX/++bLBBhvIX3/9lT0/8MADZa+99oqa37LL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"/></switch></g><ellipse cx="210.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 210.5 15 L 210.5 40 M 210.5 20 L 195.5 20 M 210.5 20 L 225.5 20 M 210.5 40 L 195.5 60 M 210.5 40 L 225.5 60" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><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: 211px;"><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;"><b>AMQP</b></div></div></div></foreignObject><image x="193" y="67.5" width="36" height="17" xlink:href="data:image/png;base64,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"/></switch></g><path d="M 210.5 181 L 210.5 216.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 210.5 221.88 L 207 214.88 L 210.5 216.63 L 214 214.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><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: 210px;"><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;">5672/tcp</div></div></div></foreignObject><image x="189" y="190.625" width="42" height="18.5" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKgAAABKCAYAAAAvxx89AAAAAXNSR0IArs4c6QAAEXVJREFUeF7tnGO0JEkThmPWtm3bnp21bdu2OWvbtm3btm3bO3ue/L6ojc6pqszq27P3VnfGOfNjbmUl3wy8EdW9+vXr10+SpB3ooTvQKwG0h55MmpbbgQTQBIQevQMJoD36eNLkEkATBnr0DiSA9ujjSZNLAE0Y6NE7kADao48nTS4BtCYYuPbaa2X55Zf/H/XSq5d8+umnMtpoo9Vk9s1PswGg5557rqy//vrN9yYiE088sbz55puV+nj22WflggsukPvuu8+9++OPP8rQQw8tY401lsw888yy0korydJLLy0DDzxwab/zzz+/66NVcscdd8hCCy0U7O7++++Xq666Sh555BF5//335ZtvvpFBBx1URhxxRJlssslkjjnmkDXWWEOmnnrqYF9FDbbYYgs55ZRT3OMZZphBnnnmmab7qtOLDQA99thjZfvtt+/S/KsA9MsvvxQ2/oorrgiOOc0008g555wjs8wyS2Hb/xqgTz31lGyyySby9NNPB+dPgyWXXFJOP/10d/GqCvv69ttvu9d22WUXOeyww6p2Ucv2DQDdb7/9ZP/99+/SQmIBymYvuOCC8u6770aPN9RQQ8nNN98svXv3zn3nvwToeeedJxtttJH8+eef0fOn4SijjCJo3CmnnDL6vbfeeksmmWSSrP2dd97p9s7KwQcfLHvuuaf7E5ocrd0O0gDQ7bbbTo477rhsXccff7yMOeaYldY5zDDDyGKLLVb6znfffedMNxuvMvzww8u6664rffr0kTHGGEM++eQTefTRR+XUU0+V77//Pms36qijyssvv+wO2hfM+xdffFFpvrbxoYceKmhFZNhhh5VXX301V9tdd911ssIKK8jff/+dvc7lWX311d382bPffvtNXnvtNbnyyivloYceapjT+OOPLy+99JJzY2Lk5JNPli233NI1ZZyvv/5aBh988IZXl1pqKbnpppvaG6DrrbeeoBlUPv7448oAjdnwjTfeWM4888ys6WyzzSZXX321jD322P29/vnnnwua8ZVXXsmecZGOOeaYmKGi26DVGEdrZ7io22yzTX/vf/vttzLFFFPIZ599lj1DW+GmjDPOOLnjnX/++bLBBhvIX3/9lT0/8MADZa+99oqa37LL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"/></switch></g><path d="M 178 181 L 178 203 L 127 203 L 127 336.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 127 341.88 L 123.5 334.88 L 127 336.63 L 130.5 334.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><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: 250px; margin-left: 126px;"><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;">80/tcp</div></div></div></foreignObject><image x="111" y="244" width="30" height="18.5" xlink:href="data:image/png;base64,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"/></switch></g><path d="M 178 181 L 178 203 L 48 203 L 48 250.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 48 255.88 L 44.5 248.88 L 48 250.63 L 51.5 248.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><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: 46px;"><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;">9000/tcp</div></div></div></foreignObject><image x="25" y="215" width="42" height="15.75" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKgAAAA/CAYAAAB0KINPAAAAAXNSR0IArs4c6QAAESxJREFUeF7tnQXQFMcSx5u4u7s7cXd3d3c34u6eQNwV4oG4C4G4u7sQd3fj1W/e663e/lYvd/cOarqKqnx3MzvTPf9p30u3wYMHD5ZIUQIdKoFuEaAdejJxW0ECEaARCB0tgQjQjj6euLkI0IiBjpZABGhHH0/cXARoxEBHSyACtKOPJ24uAnQIwcBNN90ka6211n9TL926yWeffSYTTDDBELL7xrdZCNC3335brr32WrnvvvvkzTfflK+//lr+/vtvmXjiiWXqqaeWNdZYQ9Zbbz2ZaKKJGt7BSy+9FNa499575ZNPPpHPP/9cRh555LDGzDPPLOuuu66sttpqMuqooza0xk8//SS33Xab3HDDDfLqq6+Gg+WzCSecUCaZZBJZZpllZMMNN5TZZputoeczqdU8sMbOO+8s5557btjjnHPOKc8991zD+x2SJmYC9JtvvpE99thDrrrqqgDIIgJMxxxzTBg/zDDDVOb9yy+/lF122SWAs4wA0wUXXCCrr7562dDU9zybNVirjDbeeGM566yzZOyxxy4bmnzfDh50sWmnnVbefffd8Od+++0nJ554YuV9DskDuwD09ddfl1VWWSURRlXm0HR9+/atBFIEvfDCCwdtWYeOPvpoOeSQQypN2XfffaVXr16VxuqgKaaYQh599FGZdNJJS+e1gwfdxDvvvCPTTTddsiesDZrf0nHHHScHH3xw+Oixxx6TBRdcsJSHIWFACqDffvutzDfffIJALKG51l57beEWQ4D4yiuvlPvvvz81Di166qmnFvL93XffBeG98cYbybhRRhlF1l9/fVl55ZVlsskmk59//llee+016dOnjzz77LOp51199dXBJBfReeedJzvttFNqyOyzzy5bbrmlzDLLLDLmmGMGd+Luu+8OVgKTrzT33HPLQw89JOwpj9rBg137nHPOCZYAYl9YuBFHHDG1vVVXXVVuv/32oRug2267rVx88cUJ46OPPrpcf/31stxyy2We1SWXXCLbb7994gbgvD/11FMyzzzz5B7uXnvtlQLxTDPNJAQAM844Y+Yc3IdDDz00+W6sscaS999/P4Asi/AxuUi//PJL8vWRRx4ZnsH+PL311lvBdeDSKR1xxBFy+OGH/9948Avj699yyy3h4xVXXFHuvPPO1BD6fcYff/wQI0BDpQb94IMPghn5888/E+YJLjD3RXT66acH/1Np6aWXlgEDBmROQWsBnt9++y18P9poowVn35qvrIn+4hx22GEC6LKoR48ecsYZZyRf7bjjjklwkccHAeBcc82VgBrwcwm4DJ7awYNdk/MYd9xx5ccffwwfn3LKKbLnnnumtoW1wTIoDZUAPe2001KMY27VZBQB9J9//pF55503FVXiIkwzzTRdpnltWAQ0OxnXg4hbgT3eeOMF/9UHZb///ns4TFwEvQAff/yxjDHGGIWXjC/3339/Oemkk5JxXLzdd9+97Tz4BR988EFZYoklko9ffvllmXXWWVPDsHpc4qEaoGuuuabcfPPNCZPXXHONbLDBBqUHy4CLLrpItttuu2Rsz549ZZ999ukyd4EFFpAnn3wyfA64Bg0aFHzOKrTJJpsEf1Hp4YcflkUWWSQ1FdPHxVJiT0T/VQhTP8MMMyRDl112Wenfv3/befALEvgQAEFcUi4cdN1114UUXxXiGSiHPPriiy9CNgX54erw9x9//CHjjDOOdO/eXZAF/jtuRBGResTyQFNNNZW89957yXCUHeeHC4gVwjLwPCwq/vMWW2yRmddNgiQ2wu1UYqEpp5yyCv+Ce2DHLrXUUjJw4MDU3K+++ipsQPujyTuSP6xKl112WWBC6cADD0wOTj/bbbfdQqpIiUNcZ511qi4RtL4KdYQRRhD2jB+u1A4e/GYJWp9++unwMfwTODYLoFg/rAYXQF2IPGGNNNJIwa1C8eSlEy2GcI+wfASUBMBZl92uxXisuD1jvk8Ayu389NNPkzm//vqrsKmqRP6QzUDcDG6hJVIjNtjaYYcdhGi7KnkNt8IKK8hdd92Vmr7ooovKI488knwGP3WKCF5Le1+uHTxYhgh6uNQACSJzQr4WuueeexIXBD5/+OGHZCrKwp4dGQ18c0tosE033VT69etX9QjCOKzqFVdcIcMNN1yXeQTHmnXhewLVxRdfXB5//PHKa1x44YUpdyUBKJUbImAl/D2fyihaxWofxqFt8AeVzj77bNl1112Tv0lH2eCqjAMOCaFrEOdNiF4M1oUIdPTClD1bvyfPil+shLayN7odPNi94mZttNFG4SMyEPjdWWYWoAFepSpBkrc2FFz4jIwBAEdLEkuwBxSJLdgcdNBBcuyxx3YR6/zzzx9MuBKuBeOGH374kBrETcANwHXgUmH20d6kzZTAHEEf4wLf+soHUSBfKH300UeVEtY6niT3hx9+mCskH13XNb88GMHhTkAIkPwlgoUwJzCuVNeFYF7v3r1l6623Tp7h3YhW8+BPfKuttkpMOlkGnxPW8XUBiv+OZlN3C9ATjJHyyyJSjRRilJA9eWyffSG//cQTTyTjcJOGHXbYYN59vKCDwAzz8EstP5dffnkaoKST7rjjjmQQuUluUxVC21IrV1PEHMwvZlgJTcBtVMIUU02qQwsttFDKXADWySefPDwCgVkB405gBusQiXvyjEqA1eaFW82D3ysVLT04sgwnnHBCJjt1AerPuoqy8Km+rKKMByibzcuGWEYIzgnSlShGYAlRPokGPf744wXVrYSvY81G0UFjCrntljzTJMNvvfXWZAj5T5oe6hDlPRt8ofEVlGgXWyDgcnHJ6hAVJDSLEv6WvVSt5sHulYCVoEOJ3DI55iyqA1CyAFg7VSaYUkx5VhHDruXTXeztxRdfTG3HAxTNjCVGkxYRmpx9kNVRArTIOwEoh01+TdU+fgPqGtNSRPgP5EFtSoHxl156qWy++ebJ1CJwVQWRv/n4O6wNlYGryho8Dz9KifUoVii1mge7x5NPPjlJ1eWVN3V8HYD6bAgBFKXUMsIHfeGFF0JcwT+KLJ48QNG6BD1VyGtoMgbEA6lavAcAgQiRq9bg/UKYH1IImGv8Emvi8SEQnBI+CI0YSnnJ/CJm6Ae48cYbkyGAksgdws9Zfvnlk+8222wz4TDqEBphjjnmSAES/tvFg90rvGhqZqWVVkq5X56nOgCl+HDmmWcmjzj//PNDuboZ5AFKKdxb1rx1qP7ZTANBFX0XKYACGjSmzYmRB6R+Tj4RoBJFMw7HmegODUpKgWZa2zrnfdhWaB/yg2rWW6FBSSBbt6TVPOjh4dOTttPKWVZ50x50HYBa4PMM/PS8Xou6oPUAzSqm5D0TOdt2ShQPZ9ql3Y6mBLQiZcMqhO9CcpyAxfYo+pYw2/DAcxvxQfHBaJ5WouqhTSY8j04kpUZ8UO9n6S22z9SmjVbwoOv4YC2rvNkoQH0qiMoexYBmkAcoDe951tev52WvTdmZDcsPPPBAyFlp2Spv8ySR6fLG9NKUgblQstqNz6qUKsuE5IVrU2FVS5VFa5DFsM0x3odqNQ+6t7333js0hUBE8vBZRHU0KBea5hilMvCXnYn93gO0TqEEvNiLMv3004d95r7ygQbFh8Dn45Z9//33YS+kkzCr5MXwL9RZpl5ru5gYb5s0KJHh+CvVqfXrHFtMwK2gKUQjRNwSux7Rvc3rVhE0F4yLpkSL3lFHHZX83WoedCFyuK+88kr4E0VBfrZZAEUutheXwIde2WaQByiFharvTfkAlYuEhaz80hyApYEAQGalJMhH6k3nvzWhroz7hhJqwHS9VyXWppKkWQZlwM6n8USbKbhIthG5yjp069sKiW+ObgcP7N820NBgodWkPB7qaFDbsMPzqlSdqsiOMR6gZHYItKsQVnvJJZdMhqIE0aqVAVq0CNUAcmtKWVEnDvNiiy2WjLGND1UY8CaAxK6N6HmG1+J1BMR825XO388//3wqqm8HD7aaVVTetDKrA1CKJ7aAgQxtkrzKWeSN8QAlN12WptRn4dvbwpA2HDUFoLS00fyhRFeKb07ABNPHiSaEcJ5xoquS71elsHDAAQekplNo4HMln+oqWgvNTH6PkilE9oJqhk0yt4MHAjPe7YII+p555plSEdUBKBUgqjtKBLa8hNcM8gClEaVqS6BvfN9mm21CG2dTAErJElOhZEuQlnHKiESoSrYSVCYgbpR9ByprLl0zlEOVfBRetIY3Mb6KpHNbyQN5ZHw2fXWDC2gvXN7+6wCUS2sLKLzSbTMTRTLCR9cLjHYn/UhBR8kDtKg869chF2uT+rzwSLCYABTfh2QpB88/cmNVKgykfWwJTvNXWYz6l9nQsmjGMvKvNOQFQGhBol5tG0T7cVl4bbmMrOZibF4Q10oefKBQVN60/NQBKHECTTdaVKFKxdlnvd5i16CdDwvz119/hY9x6Wxpks88QGlA0mCvTP6+G06LMAlAiYi5vfqyGQEJJrjoFVw2jY+h72uzCQBrnV27MYIWNqLvqQMgMgS2euMZQZBoT/JkSjRw2K4jOweTZU1/nia0c8jZksDWAIw9EkFa7aDjW8mDfSUG4KCtyurY7IuqGT2aSvQrILM8IkawvbR57XN2vi298nlWP29Ws0iV99p83heFQpWS6mTKxHs1S0MAZtW2semmSSFQXbINwr52nSUg+kAxDUrcZkxMVqqDzAGvbWjrFXOI3rmVtHFlERcM/9b2tpIeohMoaw7Ahw/tI+WZHDY5zzxqFQ80qqA5oLLypt0b9XTb/F3Wa8uZYvX0QgIELEaev0hwiGuj73oxnsKIPzMPUMYBNjCi/Z1eplQiySzYeMT+MEUKoETj5OBsdzYlNxpZWZyuew4eLYkDq74Si7IRojbGFBGlUtwHfD4lmlTte/HkUImgWcMWC2i/Qri2oSNrLd6twbeyTbb8jA6ONw0xpKAw/USwdM2o2eJZ5Hdx7ou6e1rBAwEYikD3UgayIu1GMErQQeKbNyOQof9VFjSgf18La4M25t0sNDfFD2RBZsHKCAVjc9q6Fw9Q8uTMpXmc5mUugKadUCSUN7F29ozBG6V0/YWXLkESv2HERu2GChH3P3CSuqia8OXWkHLit5KqEuaW6FZ/QKtsHhUufuygzv8jAv+ZBo0qr7o0mwf742DwhpWwrxIX8et7Yf1YlIe1KHyPdcLvrtuSSNWQc8h65cMDFCWA62R/cwBlpO6L3ydnDGhtH3FmFA/YMK0+2Z4lJN6i5CZW+bkYOx9zgemt8l4SrgadSXX7R9G2VGK8M+/5QNh0z1M5yvI788DRTB7sj4NVKW/6Pfn0kf0+C6B8jxIiS4DfruY7j1eARfsbkXmee+UBioUlrUihwf8KjV+Hd8ewmP53GHLTTHTS0HSMf4i/wQ3EXGAeCSLQgESPZea2TNNhRqiW4CgTYfKyHTlIyprkAWGOBHyeUMqej6bg3RduPXVnnG94QyD4vyTn0SRVX3/OWq8ZPNgfB8M0UmauQ1gKrAapGjQqwSVmkufyXn3WO0T6fM6WTjQCJ//aMS4fXVwEpWVlSw9Q+14abhfnTI8xWQMuBw3NuBMUCkh9ZWUSmpIHrSPIOHbolYAHKNka/OF/QxGg/0Z6cW5KAhGgERAdLYEI0I4+nri5CNCIgY6WQARoRx9P3FwEaMRAR0sgArSjjyduLgI0YqCjJRAB2tHHEzfXCgnERH0rpBqf2TQJRIA2TZTxQa2QQNf/L0srVonPjBJoUAIRoA0KLk5rjwQiQNsj57hKgxKIAG1QcHFaeyQQAdoeOcdVGpRABGiDgovT2iOBCND2yDmu0qAEIkAbFFyc1h4JRIC2R85xlQYlEAHaoODitPZIIAK0PXKOqzQogf8At8+PFTNbtLYAAAAASUVORK5CYII="/></switch></g><rect x="145.5" y="141" width="130" height="40" rx="6" ry="6" fill="#e6e6e6" stroke="rgb(0, 0, 0)" pointer-events="all"/><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: 161px; margin-left: 147px;"><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;">Gateway Service<br style="border-color: var(--border-color);" />(NGINX)</div></div></div></foreignObject><image x="147" y="147" width="128" height="32" xlink:href="data:image/png;base64,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"/></switch></g><ellipse cx="362" cy="40.5" rx="7.5" ry="7.5" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><path d="M 362 48 L 362 73 M 362 53 L 347 53 M 362 53 L 377 53 M 362 73 L 347 93 M 362 73 L 377 93" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><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: 100px; margin-left: 362px;"><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;"><b>JDBC</b></div></div></div></foreignObject><image x="345.5" y="100.5" width="33" height="17" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIQAAABECAYAAABArJ0TAAAAAXNSR0IArs4c6QAACU5JREFUeF7tnGXILkUUx//X7m5UbLEDuxPsblFUxMJGsf1gd4sBdnd3t6JY2N3d2L2/yzwve/fOmY0ndu/eOfB+eXfizJn/nt5nmCJFCaQkMCxKI0ogLYEIiIiHESQQAREBEQERMWBLIGqIiI6oISIGooaIGCgogWgyCgpqdBkWATG63HTBc0ZAFBRUw4aNJ2l+SbNIml7SBJLGlvSzpJ8kfSbpFUmflOW7KCAmk/R92cUl7SHpLM88DvRbyfX+kvR7sua3kj6V9KakFyU9KOnVkmulhx+X8HJAxfn/uXNwEcjnbUlvSHpE0v2O34pLjzRtRknbSlpX0mKSxiqwMLK6IwHP9ZLulPRP3pxRCRChs7wv6SJJ50j6Ju/QmefdACK01a+SLkze3KMlfVGSp/TwmdwaW0kas4t1AOrhkq4LrdEWQHTOyJt6giQuGY1ShPoFiDRPWyZv9e1FmMmMQSOcLWmiCnOtKVcmJmUnSb/4BrQNEJ0zvpSYkw0kfVBAkP0GBCz8K2kdSXcV4Kcz5IhExR9WYnyZoc8lZm1l53OMMK+tgOCQX0taxTlXIWENAhDsj9mY2zl9eZe3v9N0eePSz/EPypiU+ySt4cA6tE5RQIzrHEQfgyBtLYPzKk4ljtCBnvUmkTSFpFkTR3IFSThZefSlc8BC3nYIEIdKuiWwCRcAX7NLWj1xbjd13r41ZQfn64T4XjYB8qOSxggM4vLxBXAYn5LEOTGXOOvwskzi4G4tacUcAe0p6cz0mKKACK3L5R3bQ0B86MKpvMte2AGHSwgJ7wlJy0siIvBRCBDbJ7xcnMdI6jmhIFHP1MacayVtngOwlyXNGxhDBLOLi2byWFvJOba8RD4iRAVAQ474qAyIzgFXk3R1gvQpA9LZUdIFAwAEW+yefetS+/I28/ZatI2kSwPPb0rCbRzUP/KQkHpOyuABSYsac3ihj+88awMgOAu2+RlJkxqHRuvwJvji8F5qCLZfUBJOrY/4P5rNoqcTx3NJ4+E7khaSRDhblkhevSYJcKQJYF0lCU04nNoCCM5CVMEbZBHPff5ArwGBurcSZfc4R87HI1lH8ikW4QAyvyod5PIZgJKkGX/4KiMkCNsECAT1uCScMh9d5jJ92We9BgS5g0sMHggjjzKe7SzpXOMZ2mGugB9UBCTkMnA6g4m7tgFiw0Rl32hIh0iDrF8/AYEziZ+AecoSibLZAvUFfByiEB8d6bKMRS6+qzFtA8TErqZgxePY0mwauRsNQXTDmwcAVpW0j6QZjBs5RNIxgdsK+Q/UL6pkOkuDo22AQADPJ77CIoYkMCdPZp4NIjF1UpIqJtkUIiqUANZHaLbSlcvSaGiZU9k5/82S1jeEsZmnuNNPQJCTQN0/XOBy/gwktbD9ZULNAtv5h7RRQ1BhHAqjMsf2JZr6AQiyhvgEtzlPPq/Qhon727hFgAAgBkJtBATVwd0M6fkSVP0ARHp7+iTOd8kfq6eE3gYLNOQdJhwIGlpqMq6QRO+Aj7aQdE0NPgRbfp4krIiCSKD5CA1hOcN0Q1kapKdYaaOGoMRMEsdHa0q6uwQg6KSywtjOMrzdnQLXcq5WYaXRqR2QiaRZJUtfBWoghLNlG38qAaWNgKC9zgr9SHG/VQIQZYtbLE36HBOBA+sjwsulPQ9C0RFFKopafae2AWLmxKGkbuEjvHiaUbP1jG7yENYFofppQrHqFlRfyaqm6XJXsvatuZ+kk/uOhhb6EAjuRENwlMFR6VnqByDYI5SKJn2d7YbaKyk+nWbwTthK30m3ROvcY4lZe91ayNIQeLVzOMDQ2RwiMnCh/DzqM0uhruui/RDZNcka0vVMethHFHe4/EEBAi1A8chHlOspY6dpHleRtGRNLYPzVSW01QtuMtqLMjuVzhF8EwCBw0IOfU73BxA6Ntiyd2mmUGX7GlxuIumGAQEi1HZGTyMCfXeAgOCNJjHlI1ri1/Y84FuK+Yw5VHI3qogG7hktQ6dZmgh14QXtNNzUMpAaOW1rvq4j7C2taqE2cg5tqTOfrWTfXmuIxZ0qpNXPR5S9KX/7qF8mg/a00409qYZu53kWaq5heJEWPN+WtAKSMfUR4TAdVcMzoR2TgSqxHCA0ALbZR2gTQihf/IwTN7nR0NFLQNA3eKsL/Xw8AuolXI1jUIBAHphaWup8ZFUvkQtmweoXRdPt6qIYY+mR/k1HFEU1yz3YOw3cziDsq1WJgwnCr2xrF7E2MT9vp48IkwiXfNQLQEzrSsI4b6Fu4zOcSrQE2GsNQfUTvynrI6T3XyqQoNrYfWkVunCaW3BKSXJZvaLswZ2GnFFCXcYNZUk7gJhG0sfJAuMEuHjW9eaRXEHFwDhd0Bbx3ErqhACB+bI0EhpnOtcEQywfaq6FL5wn7Gbos8Fuuq7ZAx5wwgl5ES7ZUHi0CA8fP8G6SOad5z6mydMCmHJePNT+d84Uwwey8fVkpNcjJc7LTGvdEKXVCJ+cHZzHQcHnXARq2jp0lW87C249NIwuI8CAsELU71pGem/kgYkj9AsR2U+qtj7Hs6wcfOMx5+v5WvLSgOCS6PYJNYEWYYYPZECelSBijX4DguiIA8NLHg0KEIABe40JK0LUL2ips7qoiqzhG0OBjW82vF+RZR2NqRJ1zBc9VUHxnguNrK7jDoP9AgSeMg4bbeVFi0GDAASXQATBd5VlCRN0SqB5psx6D7no5iNrks/zxI/AySS3QNGmCGGj+fqaJNUPBSb0GhA/uv6DUyt0FvUTEACB5l6+08Q3qkr4KGQZ+UCHfEoZIiggQcbHVPfmTQzVMsZ35VpsHi1phEIUbgAMByXDRWjFZiSfiqjnbjUEIWTntxgoUvGVEx43yMcuVqFeAIK9cbYBJr4LcqFVj8pqVb6ssyyQ1EH4OInfiKBYx73w4pKD4cWEB9rx0NL4cuRg8vyoob16UdyqcglxTkMlEAHR0Iupi60IiLok39B9IyAaejF1sRUBUZfkG7pvBERDL6YutiIg6pJ8Q/eNgGjoxdTFVgREXZJv6L4REA29mLrYioCoS/IN3TcCoqEXUxdbERB1Sb6h+0ZANPRi6mIrAqIuyTd03wiIhl5MXWxFQNQl+YbuGwHR0Iupi60IiLok39B9IyAaejF1sRUBUZfkG7pvBERDL6YutiIg6pJ8Q/eNgGjoxdTF1v8DO/tUEae2xwAAAABJRU5ErkJggg=="/></switch></g><path d="M 363 264.63 L 363 192.5 L 363 119.37" fill="none" stroke="#000000" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/><path d="M 363 269.88 L 359.5 262.88 L 363 264.63 L 366.5 262.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 363 114.12 L 366.5 121.12 L 363 119.37 L 359.5 121.12 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><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: 193px; margin-left: 363px;"><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;">3307/tcp</div></div></div></foreignObject><image x="342" y="187" width="42" height="15.75" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKgAAAA/CAYAAAB0KINPAAAAAXNSR0IArs4c6QAAEZlJREFUeF7tnQW0VVUTxwcTW8EO7MTuAuwEC6UUsbC7G7sLDBABW0JFDLBQUbCxuzuwu1D51m+75qy5m3Pu2fu++6337n1n1mIp9+6zz47ZM//5z+xLiylTpkyRQooVaKIr0KJQ0Ca6M8Ww3AoUClooQpNegUJBm/T2FIMrFLTQgSa9AoWCNuntKQZXKGihA016BQoFbdLbUwyuUNAa0YFRo0bJjjvu+B/10qKFfPnllzLvvPPWyOgrH2ZZBX355Zdl6NCh8vTTT8vbb78t33//vfz9998yxxxzyIILLiirr766bLbZZrLTTjtJy5Yto0fx22+/ya233ipjx46V5557TiZNmiQ//fSTzDzzzDLnnHPK8ssvL+uss450795dlltuuej+eeCXX36Re+65R0aOHCmvv/6621g+m2+++dwcNt10U+nWrZusuOKKuf2PGzdONt5449x2oQ022GADmTBhQlDzAw88UPr37+/arrrqqvLCCy8EPVfrjVIV9K233pKDDjpIHnrooaD5tWrVSs477zzZZ5993OnOk3/++Ucuv/xyOe200+THH3/Ma+6+33bbbeXKK6+URRddNKg9jVB+5vH111/nPtOjRw+54oorZK655sps25gKuuSSS8r777/vxnbsscfK+eefnzunemgwlYLee++90rlzZ/n999+j59erVy8ZMmSITDPNNJnP0i/9855YwapibddYY43cR4855hi56KKLctvZBm3atJEnnnhCFlpoodTnGktB33vvPVlqqaWSMbEGWH4r55xzjpx00knuoyeffFLWXXfdqLk31cYlCoqbXX/99eWvv/5KxovrRqE22WQTWWSRRZzy4SbZyFtuuUV++OGHkrmdddZZyUKlTXrnnXeW22+/veSrFVZYwbnZlVde2cGHX3/9Vd544w258847p3KB88wzj2Dhy1m6AQMGyAEHHFDyDvreY489hHfxjs8//1zuv/9+NwdcvgqwZfz48Q5m+IIlfvTRRyveSyzgcccdlzx/1FFHBR2iq666ynkChHF99913MuOMM5aMo2PHjjJ69Oj6VVBqRtjEV199NZk4lgo3ufjii6duyjfffCNdunSRRx55JPl+pplmkg8//DAVwN92222yyy67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"/></switch></g><ellipse cx="58" cy="40.5" rx="7.5" ry="7.5" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><path d="M 58 48 L 58 73 M 58 53 L 43 53 M 58 53 L 73 53 M 58 73 L 43 93 M 58 73 L 73 93" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><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: 100px; margin-left: 58px;"><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;"><b>API</b></div></div></div></foreignObject><image x="48" y="100.5" width="20" height="17" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABECAYAAAAWVrIgAAAAAXNSR0IArs4c6QAABOFJREFUeF7tmVkIblMUx3/XXJQ5Q+b5liSRIcqLMYoMb1fcS917JZFZxlCGIooQ8aQQohBKZvEgeTDPQ8gcyez8tb/6bGufs89ZZ3/5uns9nrPX3mv/ztrDf50FVHMRWODyrs5UgM4kqAArQCcBp3vNwArQScDpXjOwAnQScLrXDKwAnQSc7kMycBXgM2DDlrFvApY7YlsD+Nnh/xPwPfA18CrwEvAw8G5mn23jfwhsNelnCMDDgIc6AvkG2AT4NTPguJkXoDXsX8ATwCXAcx1xFQV4N3BMBpgjgQcy2llNSgCcjPMncG2T4WcDfyTiKwZwbeBzQAN02X3AUV2NBkxgYJf/cbsTOAFQZvZZAa4lfBJwizGg9pw1o+davhsD3w6YcckMnA7nTOCaWQJ8GtgvGlBf8OKwt8SxLG32wptHBqj99fyWPlcH1m+2j12bve6AjtXyA7B9c+B9GfVXZAlvHU6x+OB5uTnptN993ECM32mz3ndkgP9aQh19rxf2u+Na2mkvvGoWAC8ALjUC0fPLwlVhD+P9tsB7PSFmZ0Bmv9qP9ZEtewrYfxYA3wR2MCJYCLwBnAtcYby/KAG+be5jA9y5OdBeSwyo/Xut0gD3Al4wAlBQu4TnOwaQcbN3wj6TmSz/NBsboPr8KuyNVhwCKJATyx4/9yJ9I7CsZflOXunWPwE63Xxv4MUeBLMn0KPP1ApSF5sBn5YCuFqQbjrZYtOSfnvq4XnA5Ua7vtKuBEDdXzdKAF8nSL8iGXgEcL8x8CvAbtFzHRhasrH1lXZjA9wc+CgB7ztg3ehd9vg5Szh1gp0DXGkEpWvN7sbzPtIuewKZS1hxnpVo+zhwYCmA+jJKfS3j2LYB3jeen9GokquN532k3ZgApdvvAlZOAFTVSFvMtGWP35WBOjh0gMSm8tCeiYC2AD4wLtV9pF32BIwYVG7bIKyC4zv0uLaWLYEfSwF8HtAJGtvp4YafWkEpv1xpNystfHIiQbI/YFsGbhedsBNY0r7Ksk9a9p9TgeuM97nSbhYA7wWOLVmNUeHxQgPCs0ZBIW62adDGKxn+OdKuNMB7Gl2/qFFPvySSYJQMVPlbB8XYliPtSgFUaU2VnPjQiOfoBqgKyjNjkwv95Ui7MQH+HlSQKukqoqqE1WVugCqaqnhayrqkXdsEpGlP6wjst3Cyap9+a8APKhdAFSR195O8KWVd0i57AoUCzB7fOoWPBrTJlrQuaZc9gUJBZo9vAXwQONwITJrRet42B5XVb0g0aJN22RP4vwHUDV4/zVc1Arsj/MXqE7P6+cIQ6+qjTdrNLcBTgOsThA5t5NsjfeiFtrcnwLdJu7kFKI1r/dfQ/Um1NJ1ufe3gFvApaTeXAHcCXk/QURYt6UsutJe41zLWH7LYUtJuLgGqkqyKsmWHAI8OBCi325qC5uKEvyXt5g6gTmPV9lTaiU1XDi1f3eiH2kEtH8CSdnMHUP9Fn0zQUfacOJTc1DLW5dz6r2JJu7kD2LbElD2POQHK/daWD7FP9Nt07gCOwGfF7KKrpL9iUukx6wqwByyraQVYAToJON1rBlaATgJO95qBFaCTgNO9ZmAF6CTgdK8ZWAE6CTjdawZWgE4CTveagRWgk4DTvWZgBegk4HSvGVgBOgk43WsGVoBOAk73moFOgH8DAtsrVLJLg14AAAAASUVORK5CYII="/></switch></g><path d="M 58 119.37 L 58 163 L 139.63 163" fill="none" stroke="#000000" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/><path d="M 58 114.12 L 61.5 121.12 L 58 119.37 L 54.5 121.12 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 144.88 163 L 137.88 166.5 L 139.63 163 L 137.88 159.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><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: 163px; margin-left: 93px;"><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;">80/tcp</div></div></div></foreignObject><image x="78" y="155.625" width="30" height="18.5" xlink:href="data:image/png;base64,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"/></switch></g><path d="M 258.5 303 L 298.25 303 L 331.63 303" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 336.88 303 L 329.88 306.5 L 331.63 303 L 329.88 299.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><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: 295px;"><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;">3306/tcp</div></div></div></foreignObject><image x="274" y="288" width="42" height="15.75" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKgAAAA/CAYAAAB0KINPAAAAAXNSR0IArs4c6QAAEqtJREFUeF7tnQWQHFUQhjtYgkNwJwnu7i4hwUJwd3d3DwkQXIJbILgmuLu7u7u7S6jvUT3V2zfyZm+5ut2arqLgdt88/V/33zJLl5EjR46USqod6KQ70KUCaCc9mWpaYQcqgFZA6NQ7UAG0Ux9PNbkKoBUGOvUOVADt1MdTTa4CaIWBTr0DFUA79fFUk6sA2iQYuOGGG6R///7/hV66dJHPPvtMJp100iaZff3TzAXoCy+8IJdffrk8/vjj8sYbb8i3334rf/31l4w//vgy5ZRTynzzzScrrLCCrLnmmtKtW7fSs/jll1/k6quvlrvuukuefvpp+fzzz+WHH36QscYaSyaYYAKZddZZZeGFF5YNNthAZpllltL988BPP/0kN910k1x33XXyyiuvhIPls8kmmyysYfnll5f1119f5phjjrr614eee+45ueSSS+T++++Xt956K4wx9thjhzHmn39+WXvttWW11VaTUUcdta5xdtxxRznzzDPDs/PMM488++yzdfXTbA+lAvT111+XnXbaSe6+++6o9XTv3l2OOeYY2XrrrcPtLpK///5bTjvtNDn88MPl+++/L2oevl9llVVkyJAhMt1000W1pxHgZx1ffvll4TMbbrihnH766TLhhBMWtrUNvvrqKwE8jFUkXIILL7xQFlhggaKmbb7v1auXvPPOO+HzfffdV4499tjSfTTjA20Aeuutt8paa60lv/76a+n1bLbZZnLBBRfIKKOMkvks/dI/45QVtCraFo1UJPvss48cf/zxRc1qvp922mnlkUcekammmirqOQCDBn7vvfei2tMI63DLLbfI0ksvHf3M22+/LTPMMEPSnj1gXCuDBg2Sgw46KHz06KOPyiKLLBLdf2duWANQzOxiiy0mf/zxRzJnTDeAWm655WSaaaYJ4MNMcpCXXXaZfPfddzXrO+qoo5KNSls4pu7aa6+t+Wq22WYLZnauueYK9OHnn3+WV199VYYPHy4PPfRQTdtJJplE0PB5mu6ss86SHXbYoeY5+t58882FsRjjk08+kdtvvz2sAXOsAm158MEHA5DyBM3PRQE8KvTLJV122WVl8sknl08//VQee+wxYT5QFxXWAN2YeOKJo7BxxhlnBEugAP/m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"/></switch></g><rect x="162.5" y="283" width="96" height="40" rx="6" ry="6" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><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: 94px; height: 1px; padding-top: 303px; margin-left: 163px;"><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<br />(Spring AMQP)</div></div></div></foreignObject><image x="163" y="289" width="94" height="32" xlink:href="data:image/png;base64,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"/></switch></g><path d="M 210.5 263 L 210.5 276.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 210.5 281.88 L 207 274.88 L 210.5 276.63 L 214 274.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><rect x="162.5" y="223" width="96" height="40" rx="6" ry="6" fill="#e6e6e6" stroke="rgb(0, 0, 0)" pointer-events="all"/><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: 94px; height: 1px; padding-top: 243px; margin-left: 163px;"><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<br style="border-color: var(--border-color);" />(RabbitMQ)</div></div></div></foreignObject><image x="163" y="229" width="94" height="32" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAXgAAACACAYAAAABK3JmAAAAAXNSR0IArs4c6QAAIABJREFUeF7t3QW0JcFRN/DC3d2d4O4uQYK7BXeCe3AJ7h8ECU4I7gR3d3d3dw0u9xemz1fbO3On58rue/dVnbNnd9+b6emu7vl3ddW/ah4mSkoDpYHSQGngIjXwMBc5qhpUaaA0UBooDUQBfC2C0kBpoDRwoRoogL/Qia1hlQZKA6WBAvhaA6WB0kBp4EI1UAB/oRNbwyoNlAZKAwXwtQZKA6WB0sCFaqAA/kIntoZVGigNlAYK4GsNlAZKA6WBC9VAAfz1m9iPiIgPSN3+5oh4les3jOpxaSB+LCJeMOnh3SPiU0ovp9NAAfzpdHmnWiqAP6+mHy4iniEiniUiHi8iHiMiHjUi/i0i/jki/joifjsifiMi/uG8Xbn41gvgzzzFVwng7dzvumG8/zO9cP8UEX8REb8WEb8YESzan93QznW7tAD+9DMGwF8/Il43Il4mIh5p4BH/HRE/HREPjogHTGtw4La6JGmgAP7My+E6A/w+1fxmRHxIRHz57m8bwSVJAfxpZ/MtIoJOn/SIZv91tyl8dER8ZET81xHt3LRbC+DPPOOXCvBNbV8XEfeOiH85sx7vZPMF8KfRNlfMZ0TE2+5p7j8jwgkRgD/K5K552D3XOz2+RkS4r2RdA4++21wfPl3mPeUKKzmRBq4ywJvoB+0Zp75bIE84+Uv9PSdfPR29T6Syu95MAfxppoDFfd+uKW6Xr4+Ir4mIn4iI3+0s8kfcrcmnj4iX3P3uzboAYWvqsyLiHU7TxWqlNHCcBq4ywAtmPf6G4T1vRLxnRLzhzD1YJqyrS5AC+ONn8Tki4mcighXf5Lci4nUi4uc3NM9v/7mTodFu4xJ8kYiHMkRKSgN3VQOXBPBNke+9Yz18XKfVS7LiC+CPf2X6gD43zHNGxO8c0PTLR8S3RdxSmdX/73VAW3VLaeCkGrhEgDcmbJpnTZrCsnmik2ru7jVWAH+87n8lIp45NfPZEfF2RzT7RbvN4U3T/Vw9TxkRf3xEm3VraeBoDVwiwFPKJ0zumnxsRn37jwWNceGguzX5hilY5v+PM/lqXzUiniYiHjki8u+XJgF/+pUi4mUj4gUmdxNeNZYF95NN50cj4nt2vtxv3RBcOgbg0flyUBEQcTM44eyTx56SqV5h56N+roh4goh43J2O/zEi/mrihX9nRHzTLqiNwTQqP7XTO9dak+fe6f3npv+8YkS8y8619vzTswQ38+9HnzF3nX6L3zQB7kD+UDEGyWe/tIv3/PL0969vCLZeJf2+745y/AZJETbDbCxt0ZG5dDJq8hVd28ewaB5h5wazRpyUXngy4LxfAuJ/OVFYv31i0j1kS6fTtd5b7aPOPvm07sVhtN/eX8/4jg3v74FdOey2SwX499mxHj62UwmA//cFNd0zIgBUE/929H7i3d8/MgF7vnUfwFsA7zxtCqMxhD+aqHpAZo3WeSjAf+DO53y/bvxvP3G4l1aPzew9IoI+H2tgidkwvngCuxHr9Yd2en/R1K5/0zeQ+ZiZ550K4G30mb1xnx1AfObA+E59yVXULyDLxo4xA3hAv0WecRcPs8ll6WNhhwL8q0XEx0eEZ6zJ307v4ucMvFutLUYF/Hjptcan3//etOa/dPD6O3bZpQI8PvL7Jy2yMlmdSwJYgE0T/37xaaHPlQFYAngg+LXTjn/IJH5ZRLz5no1Im4cAPPcBN0IWFudH7ekka4hF/kIHDIR1Y4NcC1jaSG2uTfxbdqgXf46OeCqA/5PdxvYk6bl0Q+93Uq6qfp1A/nTK4m36kFPy4RuV80HdPaxeuQaZQnoIwH/olOOysTsPNTzkPKzlKWBHCZxnA2D0WRhU7xgRDJ0rIZcK8Nweefddc6k8X0T8ZJoRGYomKjMhmmsFH1r7+M5ZLAgbQ66t4fd29y/Zgf4PRMSfTcwNJwPHPsDb0zuB/BvtWR1bAf7lJgaRI20TQUZ1P5bk0SaaoHT9LL8QEQ/cHVt/fHIzPebuCPxMky5evQs0/t3kXsFOWRIbyCunX3KDvdPOdcUV1ATgO3lxY7CsmgvnmBdIfkSeP6DzYtO4jml39N6rrl+nGae7JlxPzz46uOk692TXzqfOZKpvBXhGifWf5W8mlylWFNcn1yhDgOuRezXLp01uv6Wh2AA+v/ultWfNf8v0Ljv9MQ6sl7eKiCfrrv/0aQ1vVNd5Lr9EgAcCvQUIOIDJklgQFkgTx1Eg/yYTF5qbAs2y+fC9oOqSZGHlsC6ySKR5rz2JVhYg61H/sqDr4WLPyRaA5//8wWnRt7ZYMqyUfa4glkgOOrr2/aZj8ZJ14hTk9JI3rO+bNrKlZ9l4HbebeAZ+OvGiiKXYIAnXl3aW4igL6pr9Mf1+VfcbTBquNfOx5ibb8qy5a6+6foGXdZPFRt67XJb0ANgBfBbvpZhLli0A7x1lWGRD5SunjYgbphcGAcNKHCwLw8+67EV+A+PBu90EDlifag/NCRfb/Segz79nvH3vknLu5M8vDeAFAAFxTjsfqbaIF53dCSxtE821Y2GyDPYJ9w8/OhBqYvGxItbEIrFw9aGJujqZ5ZHbGAV4LA5B3KwLm9xrrgT/nmfa3PIzubsa8O4bj6CUU0x+CV97Av65+2wI+tNEAS9+VfkMn7SmuCN/70TFDdcLF8UXTO45/Tm1XAf9wgVJXk+VBs/l0lvPS7rhznF9k1+dkhH767cAPMB8qdQAkHY63Zc17N1Sl8rm1KTF1/q+9MaGGBI8gQFr0t+LxZff57X7z/b76wzwLZPVcclEvNaUqJKTVywgkfa/X9Hgs03Uyv4yfuQcfF1qhpUu6NNEFi6LAOiPSM/icU8LOPb3jwA86+WHu5cK8BrPWtmGz4uIt0wPZdVgiYz6FXumjqNtdsPk8WDv2ACy6DcL8tzipOFZ5mlJ/mCyxOhO8BdQHWvdXxf99pm+DCDv2Yiw9HMAdMlAGAV41T37zXbuRDDXtzeeAv/td9axuc9Gm41MDkSO+8ATrrwReYrp/uy3Z+xkt+9IOye/5ioD/DGDRYPjZwaGS8yZ3P4cwPM3Z4rXvv5w7zhCNlnz+fdtWVgCkwJvTViwLNle1gAeWwht6yXSjcbi/2sbnXsdd8UZmgg+9gHafboAArmap9iFTViQrZc5gN/yYh2zRtzLRYa5xGUzIvy9gJ77ArWVpbZFrpN+594JoL1Gg+3n34b41DujwWbZyyjAf9jOwPjgdLMNJFvl++YAnfe7JkAH6v7AhjyOPiAM7G38WzZzJS7EoZqs+fu3rJuDr700gLc7c41YENwcozK3mAFpPmYuteUYaEPJu/chvGr9Vq62iSPoHE1rH8CbT0Ha7BriP2QRczutiQBxDixb4ALCNp9R0QcsjJxYxoJnyffSA7yTj02uj2+MPvvQ6+jHXDvyb3kngBY3Ez/skp829+m66ZdhkIOrI6663vJfWsf0MgrwuOZOn03EtpAgTiU2ayf9Y9pXf0i/mrDeWfF3VbYs5nN3dGs9+LX+8Gvjvn7hADVqDuDtxt+49pCJRsjXnUXixdZaJL2VwtrmaullH8B/4sRbb/cAda6e0RR8iUX/Lz2QHxIveqv0LyQOPupqLz3As/z5qO+WsDSdIGxI9DZSF15fGRaO86zMfXzx66bfPh9hZH5sdE+bJpC7T0xjTkYBnh88n259NwIr51TCqmfpN3mbiSq5pX3vvNNdEwlXGD13tbLoVQZ4vuK1QBt/OyW2ipJoff2YWCFe2n0W1hzAjyZ3sJbVnc8i6DoSnMn3zHHVjQ27I8sSwPfggaao6qHxj8onR8S7pYsdY/eV011ql2sp5w9gM/CF9tIDPGbL64129szXcVOxwAC94mHyATLIzD2eOxD4YMnMyXXTr0A9FlN+p7gult4lfnFVOJt4h50Al758NQLwqLi9a3HU+BpZInJXvCtZ0DEzWI+0Y230GeFiB/towiPtHnXNVQb4rdUkKYKvF5e1z7wEtl7QpYU5B/DaGnFrAECBxSxYJFt3brzsPqiDYyspJ8scwLOQuHhykAhLBOtgix9RO+dI+FliMvUAT4+Zf33U4j7xzd4Vfl/uHDx97hzgMydvHRGCqb1cR/32bCMllvss8TbOvkQIw2euumu7fgTgbTK/3ynylDREAdZGxT3xknkoA6+nhp76GXvbuzSAb4NlZQisZJrXPjbIHMDb2Ue+udlXr+RH5pffKgBDcDSLEwnmxj6AR2ezGc09c9/LONe/nra4dQxL1wtK5qBvu64HeBaunIPrID7zJyFN/kPvxmK5st76cg3XUb823FzGAWABrl5gCSDGKGmyFHtpvx8BeDGA/hTKWOOCPYX0FOlTtNnaUIdKUuRdk0sFeAoFKN/faZY10btTXDIH8HPukbmJ6imSjumjvtvcniAS33WWueSS3oLft3i2Zmj2gd5TLcwl320P8GII9HmdRNEy48jZt/qvZDUfdpbrqF++aSfZnNug6F5v9XJjoZ02+fNp49t3kj0U4JcoxIesG0aU3IdzyCldSQf175IBnkJwd3PCgezQOUrcMQAvINNXIjzERSPhh4WXZc5NtATwMjxZv/zfgoVNWPgonGsUSdcLSnMvNJFc4jh8LrkEgKcb1jz3H39zk7n0/uuqX2SDnG3t1Modk0VwXhyoyVo5DNeNAPyci8Zp1wn9FMIN2ueriF1xTV17uXSA75NKHCEz+LUJPAbgBQWVQc2CIriFWujeuToYgKNPTJoDePxsgWQnFpaUxZkTvvoyrUsLV7JWtqDx+3M531Mv+EsBeHrhlxb7aWLDzZnNfn5d9at8MPptE+6RXIRO7AdI5gJu1k0u/zG3dkYAfi4IunQSP2R9yljviQzKE/QVNQ9p+67fc+kAj4WTi2qpC51rTZwC4C3kPpAiBT5XpxyZaJUd1WJpsvSRkh7gvVis7H2JG9pcCvzlvvUB40MC3SNjbdfcbYBXznkr22lpfHPBdmst1yK/rvplaHC55Br64lsteYnFm+u7jNaQHwF4+u5pjIdUt9y3Lvvqok4iEpWuvVw6wKsCp2BYE77EbGWcAuC5YyQ6Zb+7olWSX7YIiyFTC5eYJ2uZrJ7JouJeyYFNQKNqZh+0zX3si6753Zy/dcu49l17pwFelqVkMpuyP6iQTlunSKziHhNDaOLkBRgvRb/9u6Tqp4JwxFrPiUcMlbl6/v1aGAV45ANumSayRnMNo7X1iMKYYwje1zznfS2Zu1E+em0MB/3+0gEeB/XpkmaWXA7HuGg0jzMr0aHJ1m9y2hxYKfl0sVTcaQTg9QObQQwil0zFRpBNKQljTmTjcvcIMDc5Z+GvOw3wczV/TmWtie9wkzWZS6e/zvqV6Snjs0kzQGDIH6ayuZK+WPcjdZhGAb4vXsal4vSFsTYiTh+5yum9d7Vy8sc5+oQu76IifSNlTkaef9euuWSAR9HqSwQLDAkQ9XIswPdpypgDGDAj6ev6onyvjNsmuOtodnP3jwK8tgBOX3Z4rV51X8pWHyR9jb5MnkvvLCSWlz8AYE7uNMDbSB3Hc9aiJBcJTWs1Vva9pHOlbJcYQddVv2I6dNeA0omQHp2KctY2WiB64IiMAvw9ZkqPrH2NrD3f3PaUSpm2yAdNBFrF53LcasSlmceIBcfNar1jwzH6TlHaekSPi9dcKsADRwHH3h2zFPg5FuAlvOA8Zx8l5oHkpbVEIxY2GmHm7FsguTZGnsAtAO++vrqjnzneOubOiQJr/Uc1ttAXuadyGrm6NMY2t9jvNMAbr0xdfPssfMnYVYdU/wPujviZ/63AGj3O0e+us375pblmmnCbqJeUv56GLJCNlX0ANQrw2ugTrrhbvc99ImB+HnwDuPmrYUs5GX2OAite+32S1dx4bHTGAneaHOKmPQrM526+NICXcCIT05Erg62x+1KLL7DMybEAr82+VICfsdYAypL1CxRwozMjwbWsjqUSA1sBnh9YEDjXl+eGATRLx+j+iz7G4vTDbbTk3uHjpHfH6byusq+21/3dAHj9tPlnl5p+OXUpqWBDZPHtK49sfIBd0BSg9WyZtUJ111W/1mmuu2TjB/KNisyqRxXl4x6RLQAvucqzs5VtA8Vim6v/w+jy/vWZtAynPt9EX7lyGTYZN3D9xWz2ZaPCDgwjfzdhMHjfDv3Y94juhq65ygAP6B40MAoAxgrmEmEpzo2JZWYhLnHBTwHwnmvh5GCQ7osDsGgkgWDG6C9ur8QYvsCe1WNDyAW/ehVsBXj3A3OglQPBLBnW19w3KvWRzvpP9lm4fJeOn/yagrl8lTYkVLp8CvFc1pMXaukUczcAXr8E3ViE/fiarrltbLDcU9aMgCndAQ3He+ul/9Riu9cmwcjYl+BznfWb41qs5/xBGWvDmh6VLQCvzd4X72dOhmID5tP75X1iefvOQP/JvrVSGOatL4xmo0eA8EfRPpuXGBW8sbbFdXKJEP3hrpn7atSoXk523VUG+FMN0sRYdPusilMAvP5iZSiYtfSBi31jspBQOteq5B0C8J47d8JQwbL/zGDrIxCku97SHZ0XiShcVPsYKncL4I2BpSYeocjbKcQmoGImP+yaW65tMtdRv/fbbV6qg87JvXanUQSDUdkK8NrFzukzhEeeZ/Mx12sf3XaNj25n1s1I+65hscOaJffnaDsnu+6SAd5xy44/8lWWUwG8icGUuM/0EqgqOSKse9Sy/juYc/ceCvDa6j9ybbHj0C9l7alv40Qhgae3hpbGxYoCcvy1a1+BupsA3/rv9EH3NuVDXmruLpu6eRlhjmS9XUf9slznqLZOdIKVawCax38IwLufdS6xLDPkltaj+REj6AsC7nsvnQBsJNl3v/YeO0V4V87xmce1Zy/+/hIAnk/YMdpESg9HhUTh2vK1nVMCfFM2CxFocMXgnwN7wRiuJ8k1mCWOcSyevp78vgk9BuD1geshp9QDJS4c+lsSrglj4X6y+LXDwmepKsiGkYCSyUVF90t++r79qwDwrU/G6GgtExhrQ8BMPX7zyD3jJIKe54tXPiZjrXFVYY0cy5a4bvr1Qfq+bv8hheIOBXhzZjN2YvDHKZPLzJr0fvl6mD5aj/zjh/rCrXXtc2VyP1r3LXmNIWMdMM4YkVs+MHQwYG+98SoB/Na+1/WlgdJAaaA0sEcDBfC1PEoDpYHSwIVqoAD+Qie2hlUaKA2UBgrgaw2UBkoDpYEL1UAB/IVObA2rNFAaKA0UwNcaKA2UBkoDF6qBAvgLndgaVmmgNFAaKICvNVAaKA2UBi5UAwXwFzqxNazSQGmgNFAAX2ugNFAaKA1cqAYK4C90YmtYpYHSQGmgAL7WQGmgNFAauFANFMBf6MTWsEoDpYHSQAF8rYHSQGmgNHChGiiAv9CJrWGVBkoDpYEC+FoDpYHSQGngQjVQAH+hE1vDKg2UBkoDBfC1BkoDpYHSwIVqoAD+Qie2hlUaKA2UBgrgaw2UBkoDpYEL1UAB/IVObA2rNFAaKA0UwI+vgUeKiO+OiBedbvnviHj1iPim8SYu8sqPiIgPSCP75oh4lTON9IeS/j3ivSPiE87wrEeOiH/p2n3uiPi5MzyrmtyvgdeMiK+JiIZVPxARLxcR/16KW9dAAfy6jtoVD4qIe6fL3z8iPnr89ou9sgD+Yqd2aGAw5B4R8QwR8RS7DffRI+IRd5vvP0fEP0bE70fEr0TEHw+1Nn/RB+8A/sPSr75w1+5bHNHejbm1AH5squ/bgflXR8Trztz62BHxt2NNzl7lVOCl+LuI+MOI+OmdtfLDEfHgiPjXI9o9560F8Idp9zUi4utmbjXfL3ZYk7N3PU1E/HaygNtF1tbzHfgcAP4605+XjYjHHGgHwDvdfUVEfM/A9fkSOEVXTsxNznV629i1q315Afz6/HgJfiQiHmG69E8j4tki4m/OAPBLvbFpfHZEfHhEPGS9y3f0igL4/1P3m0UEMCWfMm3S+yZiCeDd80wR8esnmkWWLwu4l0MA/uEj4u0i4oMi4omO6N/PT20wXEbl8XdG1S9HxBNON/xHRLxQRPzMaAM38boC+P2z/qg7q+FnI+IZ02WvHBHfsnDbsRb82hr83Yh4rSvmC75EgDcP5jKLk9V/7ZmgP0/gA+h/b2Uy9wH8x+1iAO+7thgGfu/9/p2IeOoTAPzT71wxX3aE1T/XXSfhtxnYDNu9LPivTw392u50+7xX0OgZmJo7c0kB/H4987FzzzT5yoh4/T23zAH8j04+yJEZdfR9rMmfaVN5uJmb/joiXmp3PP6lkQbvwDWXCvBbVPd0EfFb6YZjAf7PJn/2f27pxMy1LzMRA+aa2WLBv+Bk1DzuTEP/FhGC3985uYL+MiL+ISIeZ9rwnjkiXnHaGB525n7++XtFxB8MjvVrI0LgtclHRsQHDt574y4rgF+eci/pr+5879gzRNTeYmURLckcwL9zRNz/gJX1eBHxRtNR9gm6+x1xWS77LMoDHnnQLQXwEW8SEQ88EuB/c9rYWzOvNsVeDpqU6SZ90jfi9NdcSP4/CvDckeICvZ/9nyZXFBbT3w908iknF6P+9ED/G5O7ZSR+xfDhquEuImJTXFqCuSWdBgrgl5cEaz0HUvlV331lBZ0S4NujgPt37I6mz9U9+813L+wXXYEVXQAf8RkR8Q5HAvznTH58pzjyDTtXHDfOofIYEeEkwM1IvjiB/SjAa4MxkTcG9/5iRHBVIgJsFTTjb4yI/jRgjb/CYGOfHhH3SddyHTGGSgrgh9YAf6MgV7M0WMoW+dqCPgfA6zAXAJcMfnaTc/LNh5Q0XVQA/39xmrwBH+Kiccpjnb78pFfumSfbAdlfbJmMdO1bRcTnpv+/dff/EQu+B1LNseZfaXLDHNi1h1rcmDRP0jXAukdHXhP65RLL7yeaplNKSdJAWfDzy6Ff2Eu0yP7ucwG853zVREtrz3REZmGNyrNOFiF/KlcTF5D7uZ7QMh1xf3JyC0jo+p/BhnuAl/j1qunel9xtlm84HcG9mCxKR3FBSb5b9DfW24j0iU7vtRvDJ043Yjm99uSflZQEHP2MT/iPJh8xih7rc03WEp24B7A4RoUV3J/A+iDrAyZGiL+bHEMFzLrC+JIcBNSbrAF87wpxn/jPcx7JaW/Pv+c07xmD/mQypEaSmARbM23yU3fr6l1HJ+SmXFcAf/tMAyBW06OlXwlWfe/AojgnwAOzj+/6AKAB/T55ll3g9pOTZTgwjIfGHliAAsRr0gO847cX74knF1KzSPe1w5rDptgX33B/D/DvMY3NpsUFwYrbJ/IMAOj7rOjtbgD8F0zMGTTcFlw3D+Zvq9ADv3YTiUFOCD+VfrYG8HPWu436y7d2Zs/1c89402ku1x5jXX17ugjLCYXyquaLrI3nLL8vgL9drfzu/O9NWICOkiMBzXMC/NtO4JR7/KQ7XjJAWBLsBZa/7MKtYrz8mlkXc230AI/lgCttc+DqGhXWG//sPnphD/DvMlmlGBzN1zzyPBsKNwMGyJzcDYDnmuCicHpiUDR54R0L5cdGBpWuwSyRad0ES8WpKbezD+DbyQejqwn3h/m0SZ5KBF5t6pktphSBU9+aOEU5BWZfPgrxXPLYWlsX+/sC+Nun1jH+9dKP+TFZlyNyToBHBbtf1wlAtARSXkYvcWY/cLuwevzhw2T9P0pEPNVEVVNDJjMctI2tg7WwJD3Af+m0oWCBEK4ftUS4RrgKuIZY3OimPdecK+N59oBID/DvufMFs+K5YwgL1QkCaBibDZBrgsuosS7aOFi0GE5zsgbw7nFCIYLgv9A18gJdvIY7h3sjS++iaRTcfiPfsv60b/5sksoGEIHWJ590zn/eZB/Az9Erj3EXLaj5oT+2NgBzE7EHOuU2XBMnEwlmTay9XE5k7f6L/30B/K1TTB9eRBzeJlusgnMC/HdFhLTwJiyqp92zQi12R+omwBrQsXaX5KWn4mnZGubrzLzj/t4e4DMdT+at38/5qwGkl/tFugbfcrfhcFfMSQ/w7VmO5+4TK5mT559iCzn7EpCIS2RXRrt3BODbtcbRn6IOCbLShfR/VrP2bLzE2DxjNIO5d11w63FJKX/wg0k5+wC+r/3itmc/U+6F4C8GURabHxbRmjDEGGRNvLsyXksmDRTA37oUBB8lXmRZc4Pka88F8Mol/ERXT8RLwdqbE7551nK2WiVt5WP70kvAUpNJ2QQQOgYDmjnpAb5d4+dS2vcJax47qFnDrmUNC+TNSQ/wrnEqQa/bt3G5rgc4P1sKzN1NgNcv8YQ3TgrYQontN3abmDW9BeD7ZCI8d2vglO6ZNjwxhv6EqDrpR62sHb/m4un574LDcgpKZgoQ3XSlqFD3+UkJaJEW0aicA+A9//tn0s2xMrg05sRLg7cv6OQPq4YVu3R9bsP1fJtZ+PJzQCv/bg7gZSUK9I2wIViXH9s9j3tJgaxe5gBe0C+fVPbNlRIT/NFNlub3bgO8k1QuyDXql+6t/x+f2EvGuwXge9onvb/46Euw8TpGptNJpgDb4ARbR0TsJtMtuWxy0tlIGxd7TVnwt07tJ3XJTI0RMroATgnwfOcWq2JR2WWkL1v9suZ5lPao/f6l2ec2mQN4lrufj4g6KT1/WdLQZw0CPOABQCPCEu7dP05tappkudsAb75YofIfmtgwczmEufEKbme9vX0KzG8BeC6ifKo6NulqbW769WYjlkg1Iv2mjTaLcVZSFvxta6A/mm7l1s4B/PcNWs46w6XSatGw0FuZhNxRVhlfvHrb5xJuE0f7JoKZNr85mQN4gVJW4KgICgr0Nvm0nYsJQ6aX3oLHDBGQG2E4aWtuM8GdN+9Z7jbA60sfVB9xsWEuqbBIfLCEZdvKCGwBePfk4Py566/3602s4CUGF0+fRdxiGYO3X/ZlZcHfOr9Kj0qSadJ41qOr4NzVJFlSqHRL/vDRfq5d58tF2Q++j0HRAzyfvSDtlkQg/nOJL02i5tKPAAAM8UlEQVQElLFf1gCe60rhtVHBMAF8rRxAA1K0wixXAeAxX/iXG6tJPXWb4NJmJjsUb75JzyjZAvAYSDkPRKlqp4NziYAvo6CJjaoPvi89u3fxrfH7zzWGK9luAfyt09IfFVH51njguYVzATz+MjZEb2mOLiqnAgwaL5HiUdgkArH48XMV/owjc5O3ADw3wlrCUd9vLieJVU1QKp9jZnC9Bb/VVaVJ/cuuj7nTwlUAeH391qkSY1PFvlLVH9OVGLZB2iibbAF4iX65wN1aFdXRdbh0nXhLZoRtcdGgRebyBjZCm2NJuWhuWwP90RQobvnm6qkB/kOmxbuW4bm0mAVMvfiCkDmItXXxbwH4LdZX64dM23dLnVqigPYAP+K26MfaBxD55MUYslwVgEeblKjWZMn9YDMW2Mb4Iv7NHZXjLlsAvt8EnbBGMpK3rqt2PcZXjjN9Scci2tcuCm82fPDn+5jVof269veVBX/rFHIrZGohX/eWz4sdE2RFQ1PgLPN4v61jfWxZcBKU1HiZq+G9pR3XbgF4mZjZ3TLyrD7zUvZw+3JPvr8H+C3B3NaOZJ98/AegObHNdVcF4LmSWKRtTWAlSer6q06pmEH5IzTyDxgHWbYAfJ9Ne8ipbGTeXeMUybDKJ0kbPvfoiKDIek+a0NFc7GqkrYu7pgD+/08pXfQ8X6nzPtc3KscAvGf0NE0/G62wl/sIBPDJe3DHzMCyYGULbApSSoDqGTbH+OC5FZQB2CK9Hx9NM7M4Wls9wPvqUebsjzyzb0OizBt0N14VgNet/nQzFxfKpa3NJZppf+rbAvCfucuAxcDJYsO18Z5aekqo9uUAsOJHRDBWLCaLzWILa2zkOdfymgL4W6ett+BHi4y1Vo4FePOB85w/uiw7D5Vvy8vVp3Drn8QRVt3IV4KOAfitgU996+mpSxZjD84opB+68c3rA+lzfvyrBPBiJrkCJsaJrNIm3BFojc1qxdoCmr1sAXguq8/rGtiS0b1lSt5vJqlpKQ9irt0+c9c7nIPoW/pycdcWwN86pb0PXm0WdddH5ViA9xwvND9xdhVtSebBYOHTzMfUrR9EwMbAymiyxUWj75kRMaI7WblS1pvYYDKbqf28B/gtR/nWhlNMLoI29yGXqwTw+i2LWaJaE7VulHYmPnyhKmOTpUSfLQCPrdMXfduaEzIy766RfJcD6ogOrbbQSBu9D9473Nc4GmnnIq8pgL91Ws/Bojnkk33cDkA1y2jAt7dotLGFl+5465uamSa3BeAPecHECjItsq8pvwTwWxNwrHc0ybz55Zry7TlXDeC5S7hNmvhMXlsfgF4pC4I+i/s+lyOxBeC11VMXuS9tjKf8qMZc+YiREhf5vehZNFs3iIsE9jaoAvhbp/ccPPhDAB64sqJbRUC99NEKyUfAd5/0x2tHVoA1Wkdk7qXbAvD6hqYmODgq/MX5s3A2OP71XnoLfmvwb652iXiBuEGWqwbwfQkCpxA1V+gs+9q5VfJJKI9pK8D3m4q21grPjc6362APAkPOY8DxR5cc/QC3dnoevHcYwaCkaJK3rYFzZLIeAvA61h89/UyANH/7c24R+6oNt0OTrRYNd04fdNwK8DjtuabPvpfNJta/0EuB5blaNDjtozTS/uPY+uX5Ns+rDPD61hcgE5dRI4ibqgkQzyWBjwF4rj4bSaNetra2zO2+eZ/7gM0hGbN9Jqt3WHZySQH8bWtAHYtMz9rqdzyFDz53iqsi1+TADGDxCMQuSV9vxXFd2vmIBe9ZD55ZF/uq+82VKtiSao7/nkGKFcfNMBdUngN4NfKVtx2R/jNvS5Urj7XgRzadvh78Woq9ec9fFfMBeDGiVkK6WfVLethqwWtnLtiKdcUtor+HirwMH4z3YZEmkqtsWuJHW0SMLLO2qhZN0l65aG5dSj04sixzjZS1hXdqgHcEV0q11Qb3fPXLlRFY+jSZWiT9p/ZG6J6CqgBUCV8ficg0xX3BzKVywXM1Xnr9yaY1vuyKAmL5i0b5njmA53fGKunLxvbPErTlV85rHqsIZ7yXLQBPXz0v3RyoGbRPtgJ8X4BM8hGKYIsnKAUt8euUAK+tflP0M8bCfaeT4paSFNgtToM25TwPDBdJXYdkanMF5lMGqrGTQElZ8LetgXvMVBZkTQK8ETk1wHumF7evlSI7Fb1sTlhFrKHMJAD4QHNpU5Dogy4IcLloBEozD1ogD3NjTtAvc19w61H3nBx8/rD3b7c2JLhgB/VVAyXt5MSV/Ew5CT5h16Q9S4KYL0jNfbzDtfy60vazn9/GIGhIV71sAXhsJ3rNpR3oxKlnn2wFeG1pc65KJ8AVX9gX9zjEgvdM68iJMVMz27jo2wbppNmKms2NWT6G7/RKTMtz0K7FBMpB5JF3zTVzMRWGivVQUgB/2xpgVbDGcoIQXzgrZkTOAfCsHlSyTFvEZQe4SxUbe9DVd+4IwUuUO4AkccWn8ySVNNBEjcPIcIRWoyUL65AfGKC5rhU883PWXBN1QQRZW/BMhqXjvKCxNHIWL7DxsZL+ZV/L3M3VEj1PIJZFKNOT60ByjOex5rFl0O34qX1ysf8u7b4kqS0Arx891Y9Fqi9qCAF+GwlfcS5LfAjAG49TZV8/aE1v+ngowLuXfn0PYIn+aj3afLmJuNYQAWzy7vNtAhTPuZpH7uMS7dfayLvmmv6LTu2TkKP3X/x15aK5fYr7IOO+Lyf1d58D4D1jLtsPWwBAzyUuCZCxur1coyJZhj8XELN4MVSW1ocX1vdPiSJouf72A6Ya9sB4i3tLAg+XA6t8STIl0DU2IhY4UN+Snm4T8kGJpWzHrQA/99GSfgx93fpDAF6bff1zPxspincMwHsGnfBvC/KfAje45nD2uc0OlT6hb2u+x6HPvTb3nWKirs1gBzsqYy8HkAAIN81IkPJcAK/rPYvCz1jO/deQ2jCXvnk6pwY8dOyIzCaZS1dv92aAVzM/f7y6cbRZ8azYkbrevqX6jgvuktxfp5DsKmiJaMCTftY2FHVK6ItbYV9G71aAt7lwYyy5sYzhVADfFyCzIVqfSx9fb/o7FuBbO6x4PnQnozmrfO01c+p0mjFfa33e15aTpJIW+bR9rmzbtTFd2d8XwN8+NQKaQD0f6VnQUsDX5JwAr8SvI372rXO1yAJc+gal+eWbZuGx9rUBjLhXWOiO1fzgXAm9cC340AdLl4tBMM0GQA9YK43lgg4psNWkZ9xIvHKUFnjkM3W6AErom9pSC2a03k/Pl8/BY+NC7zReH0sBekBAP7k1WL5qpM99CrAf+1aAd7/cBScZcYdWjphLyrNZqeIo2Ud+qAXfFyCTxfpOawvzSBfNXPMCmwDVvAr6MyiwtfoyAd4l88w1qIxFO/kNdHnvJX1Cnxr23I5ccyWTBgrg55dCb5Weux52LcjSwCVoAJ6If2RW1LlKDffsnqWvgF2CXg8eQwH8vOr4oFnF7QjqOK++9pbszIMnpW4sDVxjDXDROfk14dqUdTtychodNlec01x7P+VO+MjMKcsojPblSl9XAL88PVwXXBtNDilsdaUnvzpXGjiDBvrqlx7B387VdyphrWe3VAVXFzRbAL+85FjsfN6NnSFAh6pYVsKpXtNq51I1MMf02UI33qcXljoGTsuCFYfyXq4lul2qrveOqwB+/7T3fPK5j0PcyIVTgy4N7NGAYl8yeXPyFyBGsVSi4JiPcWC4Ce422Vp98kZNXAH8/unG+EDr4kNssu/Dxzdq8dRgSwN7NNDXdWqXyrNQ78hJGNBjvmBV3X9AmxhSSkQ3ccK2mTxk4N4beUkB/Pq0y+xE42tHQglByvbuS8hZb7WuKA1ctgZQVDFd+lIUc6NeK7TmHlmxkuFQfQnaLoqmhL+SBQ0UwI8tDWnt6r80mftQ81hLdVVp4OZogFGklIWKodld02tgDeDhlEJkcgea7CthfXM0vDLSAvjxpSC9XZnUJmvV+8ZbritLA5etAYlfag9JGPRvCVGK0an7xGXDYHrgHhVIrPP93Sb8+Cq/lhTAn2wNYNN8d0TIniT4vSrkqaRXUhooDZxHA6x21nszRn1r4J67KqtYbSUF8LUGSgOlgdLAzdRAuWhu5rzXqEsDpYEboIEC+BswyTXE0kBp4GZqoAD+Zs57jbo0UBq4ARoogL8Bk1xDLA2UBm6mBgrgb+a816hLA6WBG6CBAvgbMMk1xNJAaeBmaqAA/mbOe426NFAauAEaKIC/AZNcQywNlAZupgYK4G/mvNeoSwOlgRuggQL4GzDJNcTSQGngZmqgAP5mznuNujRQGrgBGiiAvwGTXEMsDZQGbqYGCuBv5rzXqEsDpYEboIEC+BswyTXE0kBp4GZqoAD+Zs57jbo0UBq4ARoogL8Bk1xDLA2UBm6mBgrgb+a816hLA6WBG6CB/wUO3mwXrERG2QAAAABJRU5ErkJggg=="/></switch></g><path d="M 175 363 L 293 363 L 293 303 L 331.63 303" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 336.88 303 L 329.88 306.5 L 331.63 303 L 329.88 299.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><rect x="79" y="343" width="96" height="40" rx="6" ry="6" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><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: 94px; height: 1px; padding-top: 363px; margin-left: 80px;"><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<br />(Spring AMQP)</div></div></div></foreignObject><image x="80" y="349" width="94" height="32" xlink:href="data:image/png;base64,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"/></switch></g><path d="M 48 297 L 48 363 L 72.63 363" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 77.88 363 L 70.88 366.5 L 72.63 363 L 70.88 359.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><rect x="0" y="257" width="96" height="40" rx="6" ry="6" fill="#e6e6e6" stroke="rgb(0, 0, 0)" pointer-events="all"/><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: 94px; height: 1px; padding-top: 277px; margin-left: 1px;"><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;">Storage Service<br />(SeaweedFS)</div></div></div></foreignObject><image x="1" y="263" width="94" height="32" xlink:href="data:image/png;base64,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"/></switch></g><path d="M 338 279.6 C 338 274.85 349.19 271 363 271 C 369.63 271 375.99 271.91 380.68 273.52 C 385.37 275.13 388 277.32 388 279.6 L 388 326.4 C 388 331.15 376.81 335 363 335 C 349.19 335 338 331.15 338 326.4 Z" fill="#dae8fc" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 388 279.6 C 388 284.35 376.81 288.2 363 288.2 C 349.19 288.2 338 284.35 338 279.6" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><rect x="322" y="333" width="85" height="20" fill="none" stroke="none" pointer-events="all"/><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: 343px; margin-left: 320px;"><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="320" y="336.5" width="89" height="17" xlink:href="data:image/png;base64,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"/></switch></g><rect x="210.5" y="403" width="30" height="16" fill="#e6e6e6" stroke="rgb(0, 0, 0)" pointer-events="all"/><rect x="248" y="403" width="140" height="16" fill="none" stroke="none" pointer-events="all"/><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: 138px; height: 1px; padding-top: 411px; margin-left: 250px;"><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;">External images</div></div></div></foreignObject><image x="250" y="404.5" width="138" height="17" xlink:href="data:image/png;base64,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"/></switch></g><rect x="210.5" y="423" width="30" height="16" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><rect x="248" y="423" width="140" height="16" fill="none" stroke="none" pointer-events="all"/><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: 138px; height: 1px; padding-top: 431px; margin-left: 250px;"><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="250" y="424.5" width="138" height="17" xlink:href="data:image/png;base64,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"/></switch></g><rect x="225.5" y="403" width="15" height="16" fill="#dae8fc" stroke="#000000" pointer-events="all"/></g></svg> \ No newline at end of file diff --git a/.docs/stylesheets/extra.css b/.docs/stylesheets/extra.css index 3275909e35faa14a0971ae45755452b10e216ab4..6d045c82da403138bbce2764c87965ecd912c76a 100644 --- a/.docs/stylesheets/extra.css +++ b/.docs/stylesheets/extra.css @@ -9,14 +9,14 @@ figure img.img-border { border: 1px solid #b3b3b3; } -.md-main .md-content a:not(.action-button), -.md-main .md-content a:not(.action-button) { +.md-main .md-content a:not(.action-button):not([tabindex]), +.md-main .md-content a:not(.action-button):not([tabindex]) { color: var(--md-typeset-color); border-bottom: 2px solid var(--md-primary-fg-color); } -.md-main .md-content a:not(.action-button):focus, -.md-main .md-content a:not(.action-button):hover { +.md-main .md-content a:not(.action-button):not([tabindex]):focus, +.md-main .md-content a:not(.action-button):not([tabindex]):hover { color: var(--md-typeset-color); border-bottom: 2px solid var(--md-primary-fg-color--dark); } diff --git a/.docs/system-databases-auth.md b/.docs/system-databases-authentication.md similarity index 96% rename from .docs/system-databases-auth.md rename to .docs/system-databases-authentication.md index 90ba31bcf55c6e53ef2471f45911c02a69d425fa..42b729403f03dab8cae8a0d31ea9fbcf06e819f2 100644 --- a/.docs/system-databases-auth.md +++ b/.docs/system-databases-authentication.md @@ -2,7 +2,7 @@ author: Martin Weise --- -# Auth Database +# Authentication Database ## tl;dr diff --git a/.docs/system-databases-data.md b/.docs/system-databases-data.md index 7c31d5e967951b287104a29d0978f6f3b8577202..e290bc1342373ea784d25c6ef2da6eb840abd8bd 100644 --- a/.docs/system-databases-data.md +++ b/.docs/system-databases-data.md @@ -25,13 +25,15 @@ author: Martin Weise By default, only one Data Database is deployed. You can deploy multiple (different) Data Database instances and make them available in the repository as follows: -```console -curl \ - -sSL \ - http://<hostname>/api/container \ - -X POST \ - -d '{"name": "Data Database 2", "imageId": 1, "host": "example.com", "port": 3306, "privilegedUsername": "root", "privilegedPassword": "s3cr3t" }' -``` +=== "Terminal" + + ```shell + curl \ + -sSL \ + http://<hostname>/api/container \ + -X POST \ + -d '{"name": "Data Database 2", "imageId": 1, "host": "example.com", "port": 3306, "privilegedUsername": "root", "privilegedPassword": "s3cr3t" }' + ``` ### Settings @@ -71,23 +73,27 @@ natively. Export all databases with `--skip-lock-tables` option for MariaDB Galera clusters as it is not supported currently by MariaDB Galera. -```console -mariadb \ - -u <privilegedUsername> \ - -p<privilegedPassword> \ - --complete-insert \ - --skip-lock-tables \ - --skip-add-locks \ - --all-databases > dump.sql -``` +=== "Terminal" + + ```shell + mariadb \ + -u <privilegedUsername> \ + -p<privilegedPassword> \ + --complete-insert \ + --skip-lock-tables \ + --skip-add-locks \ + --all-databases > dump.sql + ``` ### Restore -```console -mariadb \ - -u <privilegedUsername> \ - -p<privilegedPassword> < dump.sql -``` +=== "Terminal" + + ```shell + mariadb \ + -u <privilegedUsername> \ + -p<privilegedPassword> < dump.sql + ``` ## Limitations diff --git a/.docs/system-other-search-dashboard.md b/.docs/system-other-search-dashboard.md index a3d0e9ae12c590a226eb94afcc3c8034e4376eca..dd23d56c6784a6765f2b9b403632a209ac045932 100644 --- a/.docs/system-other-search-dashboard.md +++ b/.docs/system-other-search-dashboard.md @@ -27,6 +27,12 @@ the [Search Database](../system-databases-search). (none) +!!! 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/system-other-ui.md b/.docs/system-other-ui.md index 955120bb3e1ed87978ae58bea95f6f51362c78c6..b41eae9a9e2fb6c09ab0a98d09aa40db8c9fb12c 100644 --- a/.docs/system-other-ui.md +++ b/.docs/system-other-ui.md @@ -45,17 +45,17 @@ configured as well via the `dbrepo.config.json` values file. The important links ```json title="dbrepo.config.json" { - "title": "Database Repository", - "version": "__APPVERSION___DOCKER-COMPOSE", - "logo": { - "path": "/my_logo.png" - }, - "page": { + "title": "Database Repository", + "version": "__APPVERSION___DOCKER-COMPOSE", + "logo": { + "path": "/my_logo.png" + }, + "page": { "information": { "links": [] } - }, - ... + }, + ... } ``` @@ -95,20 +95,20 @@ The response looks like this: ```json { - "fieldname": "file", - "originalname": "gps.csv", - "encoding": "7bit", - "mimetype": "text/csv", - "buffer": { - "type": "Buffer", - "data": [ - 34, - 73, - ... - ] - }, - "size": 130279, - "etag": "9d23e73f4ed9f7e5afc80e696db69ebb" + "fieldname": "file", + "originalname": "gps.csv", + "encoding": "7bit", + "mimetype": "text/csv", + "buffer": { + "type": "Buffer", + "data": [ + 34, + 73, + ... + ] + }, + "size": 130279, + "etag": "9d23e73f4ed9f7e5afc80e696db69ebb" } ``` @@ -116,6 +116,12 @@ The response looks like this: (none) +!!! 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/system-services-authentication.md b/.docs/system-services-authentication.md index 0f1d32f3291292f489f10042ac280f47debe2499..5f6d982a0e5c0194b0da9d2e33e4e2b3194f122c 100644 --- a/.docs/system-services-authentication.md +++ b/.docs/system-services-authentication.md @@ -11,19 +11,13 @@ author: Martin Weise Image: [`dbrepo/authentication-service:__APPVERSION__`](https://hub.docker.com/r/dbrepo/authentication-service) * Ports: 8080/tcp - * Health: `http://<hostname>:8080/api/auth/health` - * Prometheus: `http://<hostname>:8080/api/auth/metrics` * UI: `http://<hostname>/api/auth/admin/` ## Overview -From version 1.2 onwards we use Keycloak for authentication for managing a part of the user identity and deprecated the -Spring Boot application instead. Going forward, the authentication will be -through [Keycloak by RedHat](https://quay.io/repository/keycloak/keycloak?tab=info). - -By default, users are created using the [UI](../system-other-ui) and the sign-up page in the UI. A new user is also -created in the UI creates a new user in the [Auth Database](../system-databases-auth), consequently a part of the -user identity is managed by Keycloak. +By default, users are created using the [User Interface](../system-other-ui) and the sign-up page in the User Interface. +This creates a new user in the [Authentication Database](../system-databases-authentication), the user identity is then managed by the +Authentication Service. ## Groups @@ -203,6 +197,7 @@ public ResponseEntity<DatabaseBriefDto> create(@NotNull Long containerId, * No support for sending e-mails through Keycloak by default. * No support for temporary passwords. +* No support for adding identifies in Keycloak directly. * No support for multi-factor authentication. !!! question "Do you miss functionality? Do these limitations affect you?" diff --git a/.docs/system-services-gateway.md b/.docs/system-services-gateway.md index 718e6c0eb520de12ff91978ac9a1c209b1001ca5..9950110c71c6a86088e3e530f59a5d5bca6935f7 100644 --- a/.docs/system-services-gateway.md +++ b/.docs/system-services-gateway.md @@ -60,6 +60,13 @@ services: (none relevant to DBRepo) +!!! 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 1. Enable TLS encryption by downloading diff --git a/.docs/system-services-search.md b/.docs/system-services-search.md index 85bba96e9f38cbb5265fc7c1d2207d809d08ce44..59dcf2081323e574ec54aff43552c949eab8008a 100644 --- a/.docs/system-services-search.md +++ b/.docs/system-services-search.md @@ -29,7 +29,7 @@ that holds all the metadata information which is mirrored from the [Metadata Dat <figure markdown>  -<figcaption>Statistical properties in Metadata Database and Search Database</figcaption> +<figcaption>Figure 1: Statistical properties in Metadata Database and Search Database</figcaption> </figure> ## Faceted Browsing @@ -54,7 +54,7 @@ the units of measurements can be transformed. <figure markdown>  -<figcaption>Two tables with compatible semantic concepts and units of measurement</figcaption> +<figcaption>Figure 2: Two tables with compatible semantic concepts and units of measurement</figcaption> </figure> In short, the search service transforms the statistical properties not in the target unit of measurements is transformed @@ -66,12 +66,12 @@ between 32 - 50 °F"* instead. <figure markdown>  -<figcaption>Unit independent search query transformation</figcaption> +<figcaption>Figure 3: Unit independent search query transformation</figcaption> </figure> ## Examples -TBD +View [usage examples](../usage-search/). ## Limitations diff --git a/.docs/system.md b/.docs/system.md index c1cc7725842803ad95154238dab2526a455c3d1e..12b6553820e14feae108f51e4ce0649d81227e66 100644 --- a/.docs/system.md +++ b/.docs/system.md @@ -6,14 +6,22 @@ author: Martin Weise !!! abstract "Abstract" - This is the full system description from a technical/developer view. + This is the full system description from a technical/developer view and continously being updated as the development + progresses. -We invite all open-source developers to help us fixing bugs and introducing features to the source code. Get involved by -sending a mail to Prof. Andreas Rauber and Projektass. Martin Weise. - -## Data Ingest +## Usage <figure markdown>  -<figcaption>Modes of data ingest</figcaption> +<figcaption>Figure 1: Modes of data ingest</figcaption> </figure> + +More [usage examples](../usage-overview/) include how to ingest datasets, data dumps, live data, etc. + +## 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! \ No newline at end of file diff --git a/.docs/usage-analyse.md b/.docs/usage-analyse.md index 92e4b5c15417357e21847c7d5ae61e6ac70fe781..8e3234cc0c1229bc66434ea69838f293228fa0a0 100644 --- a/.docs/usage-analyse.md +++ b/.docs/usage-analyse.md @@ -10,7 +10,7 @@ containing GPS-data `gps.csv` already uploaded in the `dbrepo-upload` bucket of ```shell curl -X POST \ -d '{"filename":"gps.csv","separator":","}' - http://<hostname>:5000/api/analyse/determinedt + http://<hostname>/api/analyse/determinedt ``` This results in the response: diff --git a/.docs/usage-auth.md b/.docs/usage-authentication.md similarity index 51% rename from .docs/usage-auth.md rename to .docs/usage-authentication.md index 6b1967ca0544699a671db371855091046ba7e922..21a27cb9379e0f413c3a26e15d703f24fa53d584 100644 --- a/.docs/usage-auth.md +++ b/.docs/usage-authentication.md @@ -10,7 +10,7 @@ Access tokens are needed for almost all operations. === "Terminal" - ``` console + ```shell curl -X POST \ -d "username=foo&password=bar&grant_type=password&client_id=dbrepo-client&scope=openid&client_secret=MUwRc7yfXSJwX8AdRMWaQC3Nep1VjwgG" \ http://localhost/api/auth/realms/dbrepo/protocol/openid-connect/token @@ -18,18 +18,18 @@ Access tokens are needed for almost all operations. === "Python" - ``` py - import requests - - auth = requests.post("http://localhost/api/auth/realms/dbrepo/protocol/openid-connect/token", data={ - "username": "foo", - "password": "bar", - "grant_type": "password", - "client_id": "dbrepo-client", - "scope": "openid", - "client_secret": "MUwRc7yfXSJwX8AdRMWaQC3Nep1VjwgG" - }) - print(auth.json()["access_token"]) + ```python + from keycloak import KeycloakOpenID + + # Configure client + openid = KeycloakOpenID(server_url="http://<hostname>/api/auth", + realm_name="dbrepo", client_id="dbrepo-client", + client_secret_key="MUwRc7yfXSJwX8AdRMWaQC3Nep1VjwgG") + + # Get Token + token = openid.token("username", "password") + access_token = token['access_token'] + refresh_token = token['refresh_token'] ``` ## Refresh Access Token @@ -38,7 +38,7 @@ Using the response from above, a new access token can be created via the refresh === "Terminal" - ``` console + ```shell curl -X POST \ -d "grant_type=refresh_token&client_id=dbrepo-client&refresh_token=THE_REFRESH_TOKEN&client_secret=MUwRc7yfXSJwX8AdRMWaQC3Nep1VjwgG" \ http://localhost/api/auth/realms/dbrepo/protocol/openid-connect/token @@ -46,15 +46,15 @@ Using the response from above, a new access token can be created via the refresh === "Python" - ``` py - import requests + ```python + from keycloak import KeycloakOpenID + + # Configure client + openid = KeycloakOpenID(server_url="http://<hostname>/api/auth", + realm_name="dbrepo", client_id="dbrepo-client", + client_secret_key="MUwRc7yfXSJwX8AdRMWaQC3Nep1VjwgG") - auth = requests.post("http://localhost/api/auth/realms/dbrepo/protocol/openid-connect/token", data={ - "grant_type": "refresh_token", - "client_id": "dbrepo-client", - "client_secret": "MUwRc7yfXSJwX8AdRMWaQC3Nep1VjwgG", - "refresh_token": "THE_REFRESH_TOKEN" - }) - print(auth.json()["access_token"]) + # Get Token + token = keycloak_openid.refresh_token(refresh_token) ``` diff --git a/.docs/usage-broker.md b/.docs/usage-broker.md index 501b9dcb73d29e39638c492aa127b462c9c64ce4..67f063be623d808bf72be50201a9554cf588f5f3 100644 --- a/.docs/usage-broker.md +++ b/.docs/usage-broker.md @@ -4,42 +4,49 @@ author: Martin Weise # Broker Service -## Authentication +## Preliminary -The RabbitMQ client can be authenticated through plain (username, password) and OAuth2 mechanisms. Note that the access -token already contains a field `client_id=foo`, so the username is optional in `PlainCredentials()`. +The RabbitMQ client can be authenticated through Basic Authentication (username, password) and Bearer Authentication. -=== "Plain" +!!! example "Bearer Authentication" - ``` py - import pika + Note that the encoded/signed `ACCESS_TOKEN` already contains a field `client_id=username`, so the username is + optional in `PlainCredentials` when using Bearer Authentication, but provided must match the username. + +=== "Bearer Authentication" - credentials = pika.credentials.PlainCredentials("foo", "bar") + ```python + import pika + + # Configure client + credentials = pika.credentials.PlainCredentials("", "ACCESS_TOKEN") parameters = pika.ConnectionParameters('localhost', 5672, '/', credentials) connection = pika.BlockingConnection(parameters) + + # Channel channel = connection.channel() - channel.queue_declare(queue='test', durable=True) - channel.basic_publish(exchange='', - routing_key='test', - body=b'Hello World!') + channel.basic_publish(exchange='dbrepo', + routing_key='dbrepo.database_name.table_name', + body=b'Hello World!') print(" [x] Sent 'Hello World!'") connection.close() ``` -=== "OAuth2" +=== "Basic Authentication" - ``` py + ```python import pika - credentials = pika.credentials.PlainCredentials("", "THE_ACCESS_TOKEN") + # Configure client + credentials = pika.credentials.PlainCredentials("username", "password") parameters = pika.ConnectionParameters('localhost', 5672, '/', credentials) connection = pika.BlockingConnection(parameters) + + # Channel channel = connection.channel() - channel.queue_declare(queue='test', durable=True) - channel.basic_publish(exchange='', - routing_key='test', - body=b'Hello World!') + channel.basic_publish(exchange='dbrepo', + routing_key='dbrepo.database_name.table_name', + body=b'Hello World!') print(" [x] Sent 'Hello World!'") connection.close() ``` - diff --git a/.docs/usage-metadata.md b/.docs/usage-metadata.md new file mode 100644 index 0000000000000000000000000000000000000000..690e07f4b07f4d4726693a9fd86ff5d3f37b39af --- /dev/null +++ b/.docs/usage-metadata.md @@ -0,0 +1,23 @@ +--- +author: Martin Weise +--- + +# Metadata Service + +## Preliminary + +<!-- md:version 1.4.1 --> + +!!! example "Basic Authentication" + + The use of **Basic Authentication** (username, password) instead of *Bearer Authentication* may be useful for + applications that do not have the technical capability of refreshing tokens in intervals (e.g. single-threaded + applications). It is however not recommended for any other applications as **Basic Authentication** transmits the + user password with every request. + + Additionally, performance is decreased as with every **Basic Authentication** request, an additional request is + sent to the [Authentication Service](../system-services-authentication/) where the authorization is requested before + authentication to the Metadata Service. This performance degradation should be avoided whenever possible. Use + **Bearer Authentication** instead, see how to + [obtain an access token](../usage-authentication/#obtain-access-token). + diff --git a/.docs/usage-overview.md b/.docs/usage-overview.md index 075de96375e6a1a65e70659bd4d5773f53ae1e31..f62ca1967ca23e0e4f6877e89e13e1117783d3d0 100644 --- a/.docs/usage-overview.md +++ b/.docs/usage-overview.md @@ -637,7 +637,7 @@ A user wants to import live data from e.g. sensor measurements fast and without Beware that access tokens are short lived (default is 15 minutes) and need to be refreshed regularly with refresh tokens (default is 10 days). See the usage page - on [how to refresh access tokens](../usage-auth/#refresh-access-token). + on [how to refresh access tokens](../usage-authentication/#refresh-access-token). Add a data tuple to an already existing table where the user has at least `write-own` access. @@ -699,35 +699,35 @@ A user wants to create a subset and export it as csv file. Login and select a database where you have at least `read` access (this is the case for e.g. self-created databases). Click the ":material-wrench: CREATE SUBSET" button :material-numeric-1-circle-outline: as seen in - Figure 16. + Figure 17. <figure markdown> { .img-border } - <figcaption>Figure 16: Open the create subset form.</figcaption> + <figcaption>Figure 17: Open the create subset form.</figcaption> </figure> A subset can be created by using our query builder that is visible by default in the "SIMPLE" tab. First, a source table :material-numeric-1-circle-outline: needs to be selected, then the columns that are part of the subset in :material-numeric-2-circle-outline:. Optionally the subset can be filtered. The subset query (=SQL) is displayed - in :material-numeric-3-circle-outline: in Figure 17. + in :material-numeric-3-circle-outline: in Figure 18. Once you are confident the query covers the desired result, click ":material-run: Create". <figure markdown> { .img-border } - <figcaption>Figure 17: Subset query building.</figcaption> + <figcaption>Figure 18: Subset query building.</figcaption> </figure> Once the subset is created (may take some seconds), the user is presented with the result set in :material-numeric-1-circle-outline:, more information on the subset can be obtained by clicking ":material-run: - View" on the top (c.f. Figure 18). + View" on the top (c.f. Figure 19). <figure markdown> { .img-border } - <figcaption>Figure 18: Subset result set.</figcaption> + <figcaption>Figure 19: Subset result set.</figcaption> </figure> - The subset information page in Figure 19 shows the most important metadata like subset query hash and result hash + The subset information page in Figure 20 shows the most important metadata like subset query hash and result hash (e.g. for reproducability) and subset result count. Note that although this subset is stored in the query store already, it is only temporarly stored there for 24 hours (default configuration). @@ -737,7 +737,7 @@ A user wants to create a subset and export it as csv file. <figure markdown> { .img-border } - <figcaption>Figure 19: Subset information.</figcaption> + <figcaption>Figure 20: Subset information.</figcaption> </figure> === "Terminal" diff --git a/.docs/usage-search.md b/.docs/usage-search.md new file mode 100644 index 0000000000000000000000000000000000000000..c21ae72c32bfc569fc29441cb11661f6461f5cf1 --- /dev/null +++ b/.docs/usage-search.md @@ -0,0 +1,9 @@ +--- +author: Martin Weise +--- + +# Search Service + +The Search Service connects to the [Search Database](../system-databases-search/). + +!!! note "This section will be expanded" \ No newline at end of file diff --git a/.docs/usage-storage.md b/.docs/usage-storage.md index d9fc967f28e8814619d5fa3396c4203b0e3997ab..253fe8e960814e2a91d723dd44c620726df6b7e9 100644 --- a/.docs/usage-storage.md +++ b/.docs/usage-storage.md @@ -4,9 +4,11 @@ author: Martin Weise # Storage Service +## Preliminary + Configure the credentials to access the S3 endpoint: -```console +```shell $ aws configure \ --endpoint-url http://localhost:9000 AWS Access Key ID [None]: seaweedfsadmin @@ -15,9 +17,11 @@ Default region name [None]: Default output format [None]: ``` +## Upload + Upload a CSV-file into the `dbrepo-upload` bucket with the AWS CLI: -```console +```shell $ aws --endpoint-url http://localhost:9000 \ s3 \ cp /path/to/file.csv \ @@ -25,9 +29,11 @@ $ aws --endpoint-url http://localhost:9000 \ upload: /path/to/file.csv to s3://dbrepo-upload/file.csv ``` +## List + You can list the buckets: -```console +```shell $ aws --endpoint-url http://localhost:9000 \ s3 \ ls @@ -37,7 +43,7 @@ $ aws --endpoint-url http://localhost:9000 \ And list the files in the bucket `dbrepo-upload` with: -```console +```shell $ aws --endpoint-url http://localhost:9000 \ s3 \ ls \ @@ -45,6 +51,8 @@ $ aws --endpoint-url http://localhost:9000 \ 2023-12-03 16:28:05 535219 file.csv ``` +## Other + Alternatively, you can use the middleware of the [User Interface](../system-other-ui/) to upload files. Alternatively, you can use a S3-compatible client: diff --git a/.docs/usage-upload.md b/.docs/usage-upload.md index e48bc364c1c41fc1141afd0cc2dd4ff09696c4cd..3e78928ec90f53428f6ca1293da2894c7dae2e90 100644 --- a/.docs/usage-upload.md +++ b/.docs/usage-upload.md @@ -19,8 +19,8 @@ You can also upload a file `file.csv` in 200 byte chunks with Python: === "Python" ```python - #!/bin/env python3 from tusclient import client + my_client = client.TusClient('http://localhost/api/upload/files') uploader = my_client.uploader('/path/to/file.csv', chunk_size=200) uploader.upload() diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 5db40d358078b2be2a2738f40e16af35c0584ddd..d94959dc788fecfbb358e4adaf8b5a7b1d7b3055 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -609,14 +609,14 @@ build-api-1.4: docs-registry: stage: docs - image: docker.io/python:3.9-slim + image: docker.io/python:3.11-slim only: refs: - master - release-v1.3 - release-v1.4 script: - - pip install -r ./requirements.txt + - pip install pipenv && pipenv install --dev --system --deploy - python3 .docs/docker/release.py cache: paths: @@ -642,7 +642,7 @@ docs-latest: script: - apt-get update && apt-get install -y git make sed - git fetch && git checkout master - - pip install -r ./requirements.txt + - pip install pipenv && pipenv install --dev --system --deploy - mkdir -p ./final - sed -i -e "s/__APPVERSION__/${APP_VERSION}/g" .docs/redirect.html - cp ./.docs/redirect.html ./final/index.html @@ -689,7 +689,7 @@ docs-1.3: docs-1.4: stage: docs - image: docker.io/python:3.9-slim + image: docker.io/python:3.11-slim needs: - build-api-latest - build-api-1.3 @@ -702,7 +702,7 @@ docs-1.4: script: - apt-get update && apt-get install -y git make sed wget - git fetch && git checkout release-v1.4 - - pip install -r ./.docs/requirements.txt + - pip install pipenv && pipenv install --dev --system --deploy - wget https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/raw/dev/.docs/overrides/main.html -O .docs/overrides/main.html -q - mkdir -p ./final - find .docs/ -type f -exec sed -i -e "s/__APPVERSION__/${APP_VERSION}/g" {} \; diff --git a/Pipfile b/Pipfile index 0757494bb360a3a87f122f43d490716830b47915..9307a131066c87c88b03783fc0181d3570e762fa 100644 --- a/Pipfile +++ b/Pipfile @@ -4,6 +4,13 @@ verify_ssl = true name = "pypi" [packages] +mkdocs = "1.5.3" +mkdocs-material = "9.5.5" +mkdocs-with-pdf = "0.9.3" +mkdocs-material-extensions = "*" +requests = "*" +py-dotenv = "*" +python-dotenv = "*" [dev-packages] diff --git a/Pipfile.lock b/Pipfile.lock new file mode 100644 index 0000000000000000000000000000000000000000..ae6ef935a172421420b4f84f7309c70236cc2304 --- /dev/null +++ b/Pipfile.lock @@ -0,0 +1,1003 @@ +{ + "_meta": { + "hash": { + "sha256": "f1691729be450945956d143e93645380de19a546125e08a29e5eccbf54d97e1a" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.11" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "babel": { + "hashes": [ + "sha256:6919867db036398ba21eb5c7a0f6b28ab8cbc3ae7a73a44ebe34ae74a4e7d363", + "sha256:efb1a25b7118e67ce3a259bed20545c29cb68be8ad2c784c83689981b7a57287" + ], + "markers": "python_version >= '3.7'", + "version": "==2.14.0" + }, + "beautifulsoup4": { + "hashes": [ + "sha256:74e3d1928edc070d21748185c46e3fb33490f22f52a3addee9aee0f4f7781051", + "sha256:b80878c9f40111313e55da8ba20bdba06d8fa3969fc68304167741bbf9e082ed" + ], + "markers": "python_full_version >= '3.6.0'", + "version": "==4.12.3" + }, + "brotli": { + "hashes": [ + "sha256:03d20af184290887bdea3f0f78c4f737d126c74dc2f3ccadf07e54ceca3bf208", + "sha256:0541e747cce78e24ea12d69176f6a7ddb690e62c425e01d31cc065e69ce55b48", + "sha256:069a121ac97412d1fe506da790b3e69f52254b9df4eb665cd42460c837193354", + "sha256:0b63b949ff929fbc2d6d3ce0e924c9b93c9785d877a21a1b678877ffbbc4423a", + "sha256:0c6244521dda65ea562d5a69b9a26120769b7a9fb3db2fe9545935ed6735b128", + "sha256:11d00ed0a83fa22d29bc6b64ef636c4552ebafcef57154b4ddd132f5638fbd1c", + "sha256:141bd4d93984070e097521ed07e2575b46f817d08f9fa42b16b9b5f27b5ac088", + "sha256:19c116e796420b0cee3da1ccec3b764ed2952ccfcc298b55a10e5610ad7885f9", + "sha256:1ab4fbee0b2d9098c74f3057b2bc055a8bd92ccf02f65944a241b4349229185a", + "sha256:1ae56aca0402a0f9a3431cddda62ad71666ca9d4dc3a10a142b9dce2e3c0cda3", + "sha256:224e57f6eac61cc449f498cc5f0e1725ba2071a3d4f48d5d9dffba42db196438", + "sha256:22fc2a8549ffe699bfba2256ab2ed0421a7b8fadff114a3d201794e45a9ff578", + "sha256:23032ae55523cc7bccb4f6a0bf368cd25ad9bcdcc1990b64a647e7bbcce9cb5b", + "sha256:2333e30a5e00fe0fe55903c8832e08ee9c3b1382aacf4db26664a16528d51b4b", + "sha256:2954c1c23f81c2eaf0b0717d9380bd348578a94161a65b3a2afc62c86467dd68", + "sha256:2de9d02f5bda03d27ede52e8cfe7b865b066fa49258cbab568720aa5be80a47d", + "sha256:30924eb4c57903d5a7526b08ef4a584acc22ab1ffa085faceb521521d2de32dd", + "sha256:316cc9b17edf613ac76b1f1f305d2a748f1b976b033b049a6ecdfd5612c70409", + "sha256:38025d9f30cf4634f8309c6874ef871b841eb3c347e90b0851f63d1ded5212da", + "sha256:39da8adedf6942d76dc3e46653e52df937a3c4d6d18fdc94a7c29d263b1f5b50", + "sha256:3d7954194c36e304e1523f55d7042c59dc53ec20dd4e9ea9d151f1b62b4415c0", + "sha256:4093c631e96fdd49e0377a9c167bfd75b6d0bad2ace734c6eb20b348bc3ea180", + "sha256:43ce1b9935bfa1ede40028054d7f48b5469cd02733a365eec8a329ffd342915d", + "sha256:4d4a848d1837973bf0f4b5e54e3bec977d99be36a7895c61abb659301b02c112", + "sha256:4ed11165dd45ce798d99a136808a794a748d5dc38511303239d4e2363c0695dc", + "sha256:510b5b1bfbe20e1a7b3baf5fed9e9451873559a976c1a78eebaa3b86c57b4265", + "sha256:524f35912131cc2cabb00edfd8d573b07f2d9f21fa824bd3fb19725a9cf06327", + "sha256:587ca6d3cef6e4e868102672d3bd9dc9698c309ba56d41c2b9c85bbb903cdb95", + "sha256:5b3cc074004d968722f51e550b41a27be656ec48f8afaeeb45ebf65b561481dd", + "sha256:5eeb539606f18a0b232d4ba45adccde4125592f3f636a6182b4a8a436548b914", + "sha256:5f4d5ea15c9382135076d2fb28dde923352fe02951e66935a9efaac8f10e81b0", + "sha256:5fb2ce4b8045c78ebbc7b8f3c15062e435d47e7393cc57c25115cfd49883747a", + "sha256:6172447e1b368dcbc458925e5ddaf9113477b0ed542df258d84fa28fc45ceea7", + "sha256:6c3020404e0b5eefd7c9485ccf8393cfb75ec38ce75586e046573c9dc29967a0", + "sha256:70051525001750221daa10907c77830bc889cb6d865cc0b813d9db7fefc21451", + "sha256:7905193081db9bfa73b1219140b3d315831cbff0d8941f22da695832f0dd188f", + "sha256:7c4855522edb2e6ae7fdb58e07c3ba9111e7621a8956f481c68d5d979c93032e", + "sha256:7e4c4629ddad63006efa0ef968c8e4751c5868ff0b1c5c40f76524e894c50248", + "sha256:7f4bf76817c14aa98cc6697ac02f3972cb8c3da93e9ef16b9c66573a68014f91", + "sha256:81de08ac11bcb85841e440c13611c00b67d3bf82698314928d0b676362546724", + "sha256:861bf317735688269936f755fa136a99d1ed526883859f86e41a5d43c61d8966", + "sha256:890b5a14ce214389b2cc36ce82f3093f96f4cc730c1cffdbefff77a7c71f2a97", + "sha256:89f4988c7203739d48c6f806f1e87a1d96e0806d44f0fba61dba81392c9e474d", + "sha256:8dadd1314583ec0bf2d1379f7008ad627cd6336625d6679cf2f8e67081b83acf", + "sha256:901032ff242d479a0efa956d853d16875d42157f98951c0230f69e69f9c09bac", + "sha256:906bc3a79de8c4ae5b86d3d75a8b77e44404b0f4261714306e3ad248d8ab0951", + "sha256:919e32f147ae93a09fe064d77d5ebf4e35502a8df75c29fb05788528e330fe74", + "sha256:929811df5462e182b13920da56c6e0284af407d1de637d8e536c5cd00a7daf60", + "sha256:949f3b7c29912693cee0afcf09acd6ebc04c57af949d9bf77d6101ebb61e388c", + "sha256:a090ca607cbb6a34b0391776f0cb48062081f5f60ddcce5d11838e67a01928d1", + "sha256:a1fd8a29719ccce974d523580987b7f8229aeace506952fa9ce1d53a033873c8", + "sha256:a37b8f0391212d29b3a91a799c8e4a2855e0576911cdfb2515487e30e322253d", + "sha256:a3daabb76a78f829cafc365531c972016e4aa8d5b4bf60660ad8ecee19df7ccc", + "sha256:a469274ad18dc0e4d316eefa616d1d0c2ff9da369af19fa6f3daa4f09671fd61", + "sha256:a599669fd7c47233438a56936988a2478685e74854088ef5293802123b5b2460", + "sha256:a743e5a28af5f70f9c080380a5f908d4d21d40e8f0e0c8901604d15cfa9ba751", + "sha256:a77def80806c421b4b0af06f45d65a136e7ac0bdca3c09d9e2ea4e515367c7e9", + "sha256:aac0411d20e345dc0920bdec5548e438e999ff68d77564d5e9463a7ca9d3e7b1", + "sha256:ae15b066e5ad21366600ebec29a7ccbc86812ed267e4b28e860b8ca16a2bc474", + "sha256:be36e3d172dc816333f33520154d708a2657ea63762ec16b62ece02ab5e4daf2", + "sha256:c8146669223164fc87a7e3de9f81e9423c67a79d6b3447994dfb9c95da16e2d6", + "sha256:c8fd5270e906eef71d4a8d19b7c6a43760c6abcfcc10c9101d14eb2357418de9", + "sha256:caf9ee9a5775f3111642d33b86237b05808dafcd6268faa492250e9b78046eb2", + "sha256:cdad5b9014d83ca68c25d2e9444e28e967ef16e80f6b436918c700c117a85467", + "sha256:cdbc1fc1bc0bff1cef838eafe581b55bfbffaed4ed0318b724d0b71d4d377619", + "sha256:ceb64bbc6eac5a140ca649003756940f8d6a7c444a68af170b3187623b43bebf", + "sha256:d0c5516f0aed654134a2fc936325cc2e642f8a0e096d075209672eb321cff408", + "sha256:d143fd47fad1db3d7c27a1b1d66162e855b5d50a89666af46e1679c496e8e579", + "sha256:d192f0f30804e55db0d0e0a35d83a9fead0e9a359a9ed0285dbacea60cc10a84", + "sha256:db85ecf4e609a48f4b29055f1e144231b90edc90af7481aa731ba2d059226b1b", + "sha256:de6551e370ef19f8de1807d0a9aa2cdfdce2e85ce88b122fe9f6b2b076837e59", + "sha256:e1140c64812cb9b06c922e77f1c26a75ec5e3f0fb2bf92cc8c58720dec276752", + "sha256:e6a904cb26bfefc2f0a6f240bdf5233be78cd2488900a2f846f3c3ac8489ab80", + "sha256:e84799f09591700a4154154cab9787452925578841a94321d5ee8fb9a9a328f0", + "sha256:e93dfc1a1165e385cc8239fab7c036fb2cd8093728cbd85097b284d7b99249a2", + "sha256:efa8b278894b14d6da122a72fefcebc28445f2d3f880ac59d46c90f4c13be9a3", + "sha256:f0d8a7a6b5983c2496e364b969f0e526647a06b075d034f3297dc66f3b360c64", + "sha256:f296c40e23065d0d6650c4aefe7470d2a25fffda489bcc3eb66083f3ac9f6643", + "sha256:f66b5337fa213f1da0d9000bc8dc0cb5b896b726eefd9c6046f699b169c41b9e", + "sha256:f733d788519c7e3e71f0855c96618720f5d3d60c3cb829d8bbb722dddce37985", + "sha256:fce1473f3ccc4187f75b4690cfc922628aed4d3dd013d047f95a9b3919a86596", + "sha256:fd5f17ff8f14003595ab414e45fce13d073e0762394f957182e69035c9f3d7c2", + "sha256:fdc3ff3bfccdc6b9cc7c342c03aa2400683f0cb891d46e94b64a197910dc4064" + ], + "version": "==1.1.0" + }, + "certifi": { + "hashes": [ + "sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1", + "sha256:e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474" + ], + "markers": "python_version >= '3.6'", + "version": "==2023.11.17" + }, + "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" + ], + "markers": "python_version >= '3.8'", + "version": "==1.16.0" + }, + "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" + ], + "markers": "python_full_version >= '3.7.0'", + "version": "==3.3.2" + }, + "click": { + "hashes": [ + "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28", + "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de" + ], + "markers": "python_version >= '3.7'", + "version": "==8.1.7" + }, + "colorama": { + "hashes": [ + "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", + "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6'", + "version": "==0.4.6" + }, + "cssselect2": { + "hashes": [ + "sha256:1ccd984dab89fc68955043aca4e1b03e0cf29cad9880f6e28e3ba7a74b14aa5a", + "sha256:fd23a65bfd444595913f02fc71f6b286c29261e354c41d722ca7a261a49b5969" + ], + "markers": "python_version >= '3.7'", + "version": "==0.7.0" + }, + "fonttools": { + "extras": [ + "woff" + ], + "hashes": [ + "sha256:0255dbc128fee75fb9be364806b940ed450dd6838672a150d501ee86523ac61e", + "sha256:0a00bd0e68e88987dcc047ea31c26d40a3c61185153b03457956a87e39d43c37", + "sha256:0a1d313a415eaaba2b35d6cd33536560deeebd2ed758b9bfb89ab5d97dc5deac", + "sha256:0f750037e02beb8b3569fbff701a572e62a685d2a0e840d75816592280e5feae", + "sha256:13819db8445a0cec8c3ff5f243af6418ab19175072a9a92f6cc8ca7d1452754b", + "sha256:254d9a6f7be00212bf0c3159e0a420eb19c63793b2c05e049eb337f3023c5ecc", + "sha256:29495d6d109cdbabe73cfb6f419ce67080c3ef9ea1e08d5750240fd4b0c4763b", + "sha256:32ab2e9702dff0dd4510c7bb958f265a8d3dd5c0e2547e7b5f7a3df4979abb07", + "sha256:3480eeb52770ff75140fe7d9a2ec33fb67b07efea0ab5129c7e0c6a639c40c70", + "sha256:3a808f3c1d1df1f5bf39be869b6e0c263570cdafb5bdb2df66087733f566ea71", + "sha256:3b629108351d25512d4ea1a8393a2dba325b7b7d7308116b605ea3f8e1be88df", + "sha256:3d71606c9321f6701642bd4746f99b6089e53d7e9817fc6b964e90d9c5f0ecc6", + "sha256:3e2b95dce2ead58fb12524d0ca7d63a63459dd489e7e5838c3cd53557f8933e1", + "sha256:4a5a5318ba5365d992666ac4fe35365f93004109d18858a3e18ae46f67907670", + "sha256:4c811d3c73b6abac275babb8aa439206288f56fdb2c6f8835e3d7b70de8937a7", + "sha256:4e743935139aa485fe3253fc33fe467eab6ea42583fa681223ea3f1a93dd01e6", + "sha256:4ec558c543609e71b2275c4894e93493f65d2f41c15fe1d089080c1d0bb4d635", + "sha256:5465df494f20a7d01712b072ae3ee9ad2887004701b95cb2cc6dcb9c2c97a899", + "sha256:5b60e3afa9635e3dfd3ace2757039593e3bd3cf128be0ddb7a1ff4ac45fa5a50", + "sha256:63fbed184979f09a65aa9c88b395ca539c94287ba3a364517698462e13e457c9", + "sha256:69731e8bea0578b3c28fdb43dbf95b9386e2d49a399e9a4ad736b8e479b08085", + "sha256:6dd58cc03016b281bd2c74c84cdaa6bd3ce54c5a7f47478b7657b930ac3ed8eb", + "sha256:740947906590a878a4bde7dd748e85fefa4d470a268b964748403b3ab2aeed6c", + "sha256:7df26dd3650e98ca45f1e29883c96a0b9f5bb6af8d632a6a108bc744fa0bd9b3", + "sha256:7eb7ad665258fba68fd22228a09f347469d95a97fb88198e133595947a20a184", + "sha256:7ee48bd9d6b7e8f66866c9090807e3a4a56cf43ffad48962725a190e0dd774c8", + "sha256:86e0427864c6c91cf77f16d1fb9bf1bbf7453e824589e8fb8461b6ee1144f506", + "sha256:8f57ecd742545362a0f7186774b2d1c53423ed9ece67689c93a1055b236f638c", + "sha256:90f898cdd67f52f18049250a6474185ef6544c91f27a7bee70d87d77a8daf89c", + "sha256:94208ea750e3f96e267f394d5588579bb64cc628e321dbb1d4243ffbc291b18b", + "sha256:a1c154bb85dc9a4cf145250c88d112d88eb414bad81d4cb524d06258dea1bdc0", + "sha256:a5d77479fb885ef38a16a253a2f4096bc3d14e63a56d6246bfdb56365a12b20c", + "sha256:a86a5ab2873ed2575d0fcdf1828143cfc6b977ac448e3dc616bb1e3d20efbafa", + "sha256:ac71e2e201df041a2891067dc36256755b1229ae167edbdc419b16da78732c2f", + "sha256:b3e1304e5f19ca861d86a72218ecce68f391646d85c851742d265787f55457a4", + "sha256:b8be28c036b9f186e8c7eaf8a11b42373e7e4949f9e9f370202b9da4c4c3f56c", + "sha256:c19044256c44fe299d9a73456aabee4b4d06c6b930287be93b533b4737d70aa1", + "sha256:d49ce3ea7b7173faebc5664872243b40cf88814ca3eb135c4a3cdff66af71946", + "sha256:e040f905d542362e07e72e03612a6270c33d38281fd573160e1003e43718d68d", + "sha256:eabae77a07c41ae0b35184894202305c3ad211a93b2eb53837c2a1143c8bc952", + "sha256:f791446ff297fd5f1e2247c188de53c1bfb9dd7f0549eba55b73a3c2087a2703", + "sha256:f83a4daef6d2a202acb9bf572958f91cfde5b10c8ee7fb1d09a4c81e5d851fd8" + ], + "markers": "python_version >= '3.8'", + "version": "==4.47.2" + }, + "ghp-import": { + "hashes": [ + "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619", + "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343" + ], + "version": "==2.1.0" + }, + "html5lib": { + "hashes": [ + "sha256:0d78f8fde1c230e99fe37986a60526d7049ed4bf8a9fadbad5f00e22e58e041d", + "sha256:b2e5b40261e20f354d198eae92afc10d750afb487ed5e50f9c4eaf07c184146f" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "version": "==1.1" + }, + "idna": { + "hashes": [ + "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca", + "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f" + ], + "markers": "python_version >= '3.5'", + "version": "==3.6" + }, + "jinja2": { + "hashes": [ + "sha256:7d6d50dd97d52cbc355597bd845fabfbac3f551e1f99619e39a35ce8c370b5fa", + "sha256:ac8bd6544d4bb2c9792bf3a159e80bba8fda7f07e81bc3aed565432d5925ba90" + ], + "markers": "python_version >= '3.7'", + "version": "==3.1.3" + }, + "libsass": { + "hashes": [ + "sha256:31e86d92a5c7a551df844b72d83fc2b5e50abc6fbbb31e296f7bebd6489ed1b4", + "sha256:34cae047cbbfc4ffa832a61cbb110f3c95f5471c6170c842d3fed161e40814dc", + "sha256:4a218406d605f325d234e4678bd57126a66a88841cb95bee2caeafdc6f138306", + "sha256:6f209955ede26684e76912caf329f4ccb57e4a043fd77fe0e7348dd9574f1880", + "sha256:a2ec85d819f353cbe807432d7275d653710d12b08ec7ef61c124a580a8352f3c", + "sha256:ea97d1b45cdc2fc3590cb9d7b60f1d8915d3ce17a98c1f2d4dd47ee0d9c68ce6" + ], + "markers": "python_version >= '3.8'", + "version": "==0.23.0" + }, + "markdown": { + "hashes": [ + "sha256:d43323865d89fc0cb9b20c75fc8ad313af307cc087e84b657d9eec768eddeadd", + "sha256:e1ac7b3dc550ee80e602e71c1d168002f062e49f1b11e26a36264dafd4df2ef8" + ], + "markers": "python_version >= '3.8'", + "version": "==3.5.2" + }, + "markupsafe": { + "hashes": [ + "sha256:0042d6a9880b38e1dd9ff83146cc3c9c18a059b9360ceae207805567aacccc69", + "sha256:0c26f67b3fe27302d3a412b85ef696792c4a2386293c53ba683a89562f9399b0", + "sha256:0fbad3d346df8f9d72622ac71b69565e621ada2ce6572f37c2eae8dacd60385d", + "sha256:15866d7f2dc60cfdde12ebb4e75e41be862348b4728300c36cdf405e258415ec", + "sha256:1c98c33ffe20e9a489145d97070a435ea0679fddaabcafe19982fe9c971987d5", + "sha256:21e7af8091007bf4bebf4521184f4880a6acab8df0df52ef9e513d8e5db23411", + "sha256:23984d1bdae01bee794267424af55eef4dfc038dc5d1272860669b2aa025c9e3", + "sha256:31f57d64c336b8ccb1966d156932f3daa4fee74176b0fdc48ef580be774aae74", + "sha256:3583a3a3ab7958e354dc1d25be74aee6228938312ee875a22330c4dc2e41beb0", + "sha256:36d7626a8cca4d34216875aee5a1d3d654bb3dac201c1c003d182283e3205949", + "sha256:396549cea79e8ca4ba65525470d534e8a41070e6b3500ce2414921099cb73e8d", + "sha256:3a66c36a3864df95e4f62f9167c734b3b1192cb0851b43d7cc08040c074c6279", + "sha256:3aae9af4cac263007fd6309c64c6ab4506dd2b79382d9d19a1994f9240b8db4f", + "sha256:3ab3a886a237f6e9c9f4f7d272067e712cdb4efa774bef494dccad08f39d8ae6", + "sha256:47bb5f0142b8b64ed1399b6b60f700a580335c8e1c57f2f15587bd072012decc", + "sha256:49a3b78a5af63ec10d8604180380c13dcd870aba7928c1fe04e881d5c792dc4e", + "sha256:4df98d4a9cd6a88d6a585852f56f2155c9cdb6aec78361a19f938810aa020954", + "sha256:5045e892cfdaecc5b4c01822f353cf2c8feb88a6ec1c0adef2a2e705eef0f656", + "sha256:5244324676254697fe5c181fc762284e2c5fceeb1c4e3e7f6aca2b6f107e60dc", + "sha256:54635102ba3cf5da26eb6f96c4b8c53af8a9c0d97b64bdcb592596a6255d8518", + "sha256:54a7e1380dfece8847c71bf7e33da5d084e9b889c75eca19100ef98027bd9f56", + "sha256:55d03fea4c4e9fd0ad75dc2e7e2b6757b80c152c032ea1d1de487461d8140efc", + "sha256:698e84142f3f884114ea8cf83e7a67ca8f4ace8454e78fe960646c6c91c63bfa", + "sha256:6aa5e2e7fc9bc042ae82d8b79d795b9a62bd8f15ba1e7594e3db243f158b5565", + "sha256:7653fa39578957bc42e5ebc15cf4361d9e0ee4b702d7d5ec96cdac860953c5b4", + "sha256:765f036a3d00395a326df2835d8f86b637dbaf9832f90f5d196c3b8a7a5080cb", + "sha256:78bc995e004681246e85e28e068111a4c3f35f34e6c62da1471e844ee1446250", + "sha256:7a07f40ef8f0fbc5ef1000d0c78771f4d5ca03b4953fc162749772916b298fc4", + "sha256:8b570a1537367b52396e53325769608f2a687ec9a4363647af1cded8928af959", + "sha256:987d13fe1d23e12a66ca2073b8d2e2a75cec2ecb8eab43ff5624ba0ad42764bc", + "sha256:9896fca4a8eb246defc8b2a7ac77ef7553b638e04fbf170bff78a40fa8a91474", + "sha256:9e9e3c4020aa2dc62d5dd6743a69e399ce3de58320522948af6140ac959ab863", + "sha256:a0b838c37ba596fcbfca71651a104a611543077156cb0a26fe0c475e1f152ee8", + "sha256:a4d176cfdfde84f732c4a53109b293d05883e952bbba68b857ae446fa3119b4f", + "sha256:a76055d5cb1c23485d7ddae533229039b850db711c554a12ea64a0fd8a0129e2", + "sha256:a76cd37d229fc385738bd1ce4cba2a121cf26b53864c1772694ad0ad348e509e", + "sha256:a7cc49ef48a3c7a0005a949f3c04f8baa5409d3f663a1b36f0eba9bfe2a0396e", + "sha256:abf5ebbec056817057bfafc0445916bb688a255a5146f900445d081db08cbabb", + "sha256:b0fe73bac2fed83839dbdbe6da84ae2a31c11cfc1c777a40dbd8ac8a6ed1560f", + "sha256:b6f14a9cd50c3cb100eb94b3273131c80d102e19bb20253ac7bd7336118a673a", + "sha256:b83041cda633871572f0d3c41dddd5582ad7d22f65a72eacd8d3d6d00291df26", + "sha256:b835aba863195269ea358cecc21b400276747cc977492319fd7682b8cd2c253d", + "sha256:bf1196dcc239e608605b716e7b166eb5faf4bc192f8a44b81e85251e62584bd2", + "sha256:c669391319973e49a7c6230c218a1e3044710bc1ce4c8e6eb71f7e6d43a2c131", + "sha256:c7556bafeaa0a50e2fe7dc86e0382dea349ebcad8f010d5a7dc6ba568eaaa789", + "sha256:c8f253a84dbd2c63c19590fa86a032ef3d8cc18923b8049d91bcdeeb2581fbf6", + "sha256:d18b66fe626ac412d96c2ab536306c736c66cf2a31c243a45025156cc190dc8a", + "sha256:d5291d98cd3ad9a562883468c690a2a238c4a6388ab3bd155b0c75dd55ece858", + "sha256:d5c31fe855c77cad679b302aabc42d724ed87c043b1432d457f4976add1c2c3e", + "sha256:d6e427c7378c7f1b2bef6a344c925b8b63623d3321c09a237b7cc0e77dd98ceb", + "sha256:dac1ebf6983148b45b5fa48593950f90ed6d1d26300604f321c74a9ca1609f8e", + "sha256:de8153a7aae3835484ac168a9a9bdaa0c5eee4e0bc595503c95d53b942879c84", + "sha256:e1a0d1924a5013d4f294087e00024ad25668234569289650929ab871231668e7", + "sha256:e7902211afd0af05fbadcc9a312e4cf10f27b779cf1323e78d52377ae4b72bea", + "sha256:e888ff76ceb39601c59e219f281466c6d7e66bd375b4ec1ce83bcdc68306796b", + "sha256:f06e5a9e99b7df44640767842f414ed5d7bedaaa78cd817ce04bbd6fd86e2dd6", + "sha256:f6be2d708a9d0e9b0054856f07ac7070fbe1754be40ca8525d5adccdbda8f475", + "sha256:f9917691f410a2e0897d1ef99619fd3f7dd503647c8ff2475bf90c3cf222ad74", + "sha256:fc1a75aa8f11b87910ffd98de62b29d6520b6d6e8a3de69a70ca34dea85d2a8a", + "sha256:fe8512ed897d5daf089e5bd010c3dc03bb1bdae00b35588c49b98268d4a01e00" + ], + "markers": "python_version >= '3.7'", + "version": "==2.1.4" + }, + "mergedeep": { + "hashes": [ + "sha256:0096d52e9dad9939c3d975a774666af186eda617e6ca84df4c94dec30004f2a8", + "sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307" + ], + "markers": "python_version >= '3.6'", + "version": "==1.3.4" + }, + "mkdocs": { + "hashes": [ + "sha256:3b3a78e736b31158d64dbb2f8ba29bd46a379d0c6e324c2246c3bc3d2189cfc1", + "sha256:eb7c99214dcb945313ba30426c2451b735992c73c2e10838f76d09e39ff4d0e2" + ], + "index": "pypi", + "version": "==1.5.3" + }, + "mkdocs-material": { + "hashes": [ + "sha256:4480d9580faf42fed0123d0465502bfc1c0c239ecc9c4d66159cf0459ea1b4ae", + "sha256:ac50b2431a79a3b160fdefbba37c9132485f1a69166aba115ad49fafdbbbc5df" + ], + "index": "pypi", + "version": "==9.5.5" + }, + "mkdocs-material-extensions": { + "hashes": [ + "sha256:10c9511cea88f568257f960358a467d12b970e1f7b2c0e5fb2bb48cab1928443", + "sha256:adff8b62700b25cb77b53358dad940f3ef973dd6db797907c49e3c2ef3ab4e31" + ], + "index": "pypi", + "version": "==1.3.1" + }, + "mkdocs-with-pdf": { + "hashes": [ + "sha256:002d76417b5cc584effdfdb6ec8d073266a308a85680c430562e97f00b886e49", + "sha256:bda3375d7040d1b8871da17c6d71ea736bdca6c669608f28ed62771031d2e0c6" + ], + "index": "pypi", + "version": "==0.9.3" + }, + "packaging": { + "hashes": [ + "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5", + "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7" + ], + "markers": "python_version >= '3.7'", + "version": "==23.2" + }, + "paginate": { + "hashes": [ + "sha256:5e6007b6a9398177a7e1648d04fdd9f8c9766a1a945bceac82f1929e8c78af2d" + ], + "version": "==0.5.6" + }, + "pathspec": { + "hashes": [ + "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", + "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712" + ], + "markers": "python_version >= '3.8'", + "version": "==0.12.1" + }, + "pillow": { + "hashes": [ + "sha256:0304004f8067386b477d20a518b50f3fa658a28d44e4116970abfcd94fac34a8", + "sha256:0689b5a8c5288bc0504d9fcee48f61a6a586b9b98514d7d29b840143d6734f39", + "sha256:0eae2073305f451d8ecacb5474997c08569fb4eb4ac231ffa4ad7d342fdc25ac", + "sha256:0fb3e7fc88a14eacd303e90481ad983fd5b69c761e9e6ef94c983f91025da869", + "sha256:11fa2e5984b949b0dd6d7a94d967743d87c577ff0b83392f17cb3990d0d2fd6e", + "sha256:127cee571038f252a552760076407f9cff79761c3d436a12af6000cd182a9d04", + "sha256:154e939c5f0053a383de4fd3d3da48d9427a7e985f58af8e94d0b3c9fcfcf4f9", + "sha256:15587643b9e5eb26c48e49a7b33659790d28f190fc514a322d55da2fb5c2950e", + "sha256:170aeb00224ab3dc54230c797f8404507240dd868cf52066f66a41b33169bdbe", + "sha256:1b5e1b74d1bd1b78bc3477528919414874748dd363e6272efd5abf7654e68bef", + "sha256:1da3b2703afd040cf65ec97efea81cfba59cdbed9c11d8efc5ab09df9509fc56", + "sha256:1e23412b5c41e58cec602f1135c57dfcf15482013ce6e5f093a86db69646a5aa", + "sha256:2247178effb34a77c11c0e8ac355c7a741ceca0a732b27bf11e747bbc950722f", + "sha256:257d8788df5ca62c980314053197f4d46eefedf4e6175bc9412f14412ec4ea2f", + "sha256:3031709084b6e7852d00479fd1d310b07d0ba82765f973b543c8af5061cf990e", + "sha256:322209c642aabdd6207517e9739c704dc9f9db943015535783239022002f054a", + "sha256:322bdf3c9b556e9ffb18f93462e5f749d3444ce081290352c6070d014c93feb2", + "sha256:33870dc4653c5017bf4c8873e5488d8f8d5f8935e2f1fb9a2208c47cdd66efd2", + "sha256:35bb52c37f256f662abdfa49d2dfa6ce5d93281d323a9af377a120e89a9eafb5", + "sha256:3c31822339516fb3c82d03f30e22b1d038da87ef27b6a78c9549888f8ceda39a", + "sha256:3eedd52442c0a5ff4f887fab0c1c0bb164d8635b32c894bc1faf4c618dd89df2", + "sha256:3ff074fc97dd4e80543a3e91f69d58889baf2002b6be64347ea8cf5533188213", + "sha256:47c0995fc4e7f79b5cfcab1fc437ff2890b770440f7696a3ba065ee0fd496563", + "sha256:49d9ba1ed0ef3e061088cd1e7538a0759aab559e2e0a80a36f9fd9d8c0c21591", + "sha256:51f1a1bffc50e2e9492e87d8e09a17c5eea8409cda8d3f277eb6edc82813c17c", + "sha256:52a50aa3fb3acb9cf7213573ef55d31d6eca37f5709c69e6858fe3bc04a5c2a2", + "sha256:54f1852cd531aa981bc0965b7d609f5f6cc8ce8c41b1139f6ed6b3c54ab82bfb", + "sha256:609448742444d9290fd687940ac0b57fb35e6fd92bdb65386e08e99af60bf757", + "sha256:69ffdd6120a4737710a9eee73e1d2e37db89b620f702754b8f6e62594471dee0", + "sha256:6fad5ff2f13d69b7e74ce5b4ecd12cc0ec530fcee76356cac6742785ff71c452", + "sha256:7049e301399273a0136ff39b84c3678e314f2158f50f517bc50285fb5ec847ad", + "sha256:70c61d4c475835a19b3a5aa42492409878bbca7438554a1f89d20d58a7c75c01", + "sha256:716d30ed977be8b37d3ef185fecb9e5a1d62d110dfbdcd1e2a122ab46fddb03f", + "sha256:753cd8f2086b2b80180d9b3010dd4ed147efc167c90d3bf593fe2af21265e5a5", + "sha256:773efe0603db30c281521a7c0214cad7836c03b8ccff897beae9b47c0b657d61", + "sha256:7823bdd049099efa16e4246bdf15e5a13dbb18a51b68fa06d6c1d4d8b99a796e", + "sha256:7c8f97e8e7a9009bcacbe3766a36175056c12f9a44e6e6f2d5caad06dcfbf03b", + "sha256:823ef7a27cf86df6597fa0671066c1b596f69eba53efa3d1e1cb8b30f3533068", + "sha256:8373c6c251f7ef8bda6675dd6d2b3a0fcc31edf1201266b5cf608b62a37407f9", + "sha256:83b2021f2ade7d1ed556bc50a399127d7fb245e725aa0113ebd05cfe88aaf588", + "sha256:870ea1ada0899fd0b79643990809323b389d4d1d46c192f97342eeb6ee0b8483", + "sha256:8d12251f02d69d8310b046e82572ed486685c38f02176bd08baf216746eb947f", + "sha256:9c23f307202661071d94b5e384e1e1dc7dfb972a28a2310e4ee16103e66ddb67", + "sha256:9d189550615b4948f45252d7f005e53c2040cea1af5b60d6f79491a6e147eef7", + "sha256:a086c2af425c5f62a65e12fbf385f7c9fcb8f107d0849dba5839461a129cf311", + "sha256:a2b56ba36e05f973d450582fb015594aaa78834fefe8dfb8fcd79b93e64ba4c6", + "sha256:aebb6044806f2e16ecc07b2a2637ee1ef67a11840a66752751714a0d924adf72", + "sha256:b1b3020d90c2d8e1dae29cf3ce54f8094f7938460fb5ce8bc5c01450b01fbaf6", + "sha256:b4b6b1e20608493548b1f32bce8cca185bf0480983890403d3b8753e44077129", + "sha256:b6f491cdf80ae540738859d9766783e3b3c8e5bd37f5dfa0b76abdecc5081f13", + "sha256:b792a349405fbc0163190fde0dc7b3fef3c9268292586cf5645598b48e63dc67", + "sha256:b7c2286c23cd350b80d2fc9d424fc797575fb16f854b831d16fd47ceec078f2c", + "sha256:babf5acfede515f176833ed6028754cbcd0d206f7f614ea3447d67c33be12516", + "sha256:c365fd1703040de1ec284b176d6af5abe21b427cb3a5ff68e0759e1e313a5e7e", + "sha256:c4225f5220f46b2fde568c74fca27ae9771536c2e29d7c04f4fb62c83275ac4e", + "sha256:c570f24be1e468e3f0ce7ef56a89a60f0e05b30a3669a459e419c6eac2c35364", + "sha256:c6dafac9e0f2b3c78df97e79af707cdc5ef8e88208d686a4847bab8266870023", + "sha256:c8de2789052ed501dd829e9cae8d3dcce7acb4777ea4a479c14521c942d395b1", + "sha256:cb28c753fd5eb3dd859b4ee95de66cc62af91bcff5db5f2571d32a520baf1f04", + "sha256:cb4c38abeef13c61d6916f264d4845fab99d7b711be96c326b84df9e3e0ff62d", + "sha256:d1b35bcd6c5543b9cb547dee3150c93008f8dd0f1fef78fc0cd2b141c5baf58a", + "sha256:d8e6aeb9201e655354b3ad049cb77d19813ad4ece0df1249d3c793de3774f8c7", + "sha256:d8ecd059fdaf60c1963c58ceb8997b32e9dc1b911f5da5307aab614f1ce5c2fb", + "sha256:da2b52b37dad6d9ec64e653637a096905b258d2fc2b984c41ae7d08b938a67e4", + "sha256:e87f0b2c78157e12d7686b27d63c070fd65d994e8ddae6f328e0dcf4a0cd007e", + "sha256:edca80cbfb2b68d7b56930b84a0e45ae1694aeba0541f798e908a49d66b837f1", + "sha256:f379abd2f1e3dddb2b61bc67977a6b5a0a3f7485538bcc6f39ec76163891ee48", + "sha256:fe4c15f6c9285dc54ce6553a3ce908ed37c8f3825b5a51a15c91442bb955b868" + ], + "markers": "python_version >= '3.8'", + "version": "==10.2.0" + }, + "platformdirs": { + "hashes": [ + "sha256:11c8f37bcca40db96d8144522d925583bdb7a31f7b0e37e3ed4318400a8e2380", + "sha256:906d548203468492d432bcb294d4bc2fff751bf84971fbb2c10918cc206ee420" + ], + "markers": "python_version >= '3.8'", + "version": "==4.1.0" + }, + "py-dotenv": { + "hashes": [ + "sha256:548c588c3b7e2ee2142b0ac97d2912d223ff38e874302426bbb6c21353817cc2" + ], + "index": "pypi", + "version": "==0.1" + }, + "pycparser": { + "hashes": [ + "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9", + "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206" + ], + "version": "==2.21" + }, + "pydyf": { + "hashes": [ + "sha256:901186a2e9f897108139426a6486f5225bdcc9b70be2ec965f25111e42f8ac5d", + "sha256:b22b1ef016141b54941ad66ed4e036a7bdff39c0b360993b283875c3f854dd9a" + ], + "markers": "python_version >= '3.7'", + "version": "==0.8.0" + }, + "pygments": { + "hashes": [ + "sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c", + "sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367" + ], + "markers": "python_version >= '3.7'", + "version": "==2.17.2" + }, + "pymdown-extensions": { + "hashes": [ + "sha256:6ca215bc57bc12bf32b414887a68b810637d039124ed9b2e5bd3325cbb2c050c", + "sha256:c0d64d5cf62566f59e6b2b690a4095c931107c250a8c8e1351c1de5f6b036deb" + ], + "markers": "python_version >= '3.8'", + "version": "==10.7" + }, + "pyphen": { + "hashes": [ + "sha256:414c9355958ca3c6a3ff233f65678c245b8ecb56418fb291e2b93499d61cd510", + "sha256:596c8b3be1c1a70411ba5f6517d9ccfe3083c758ae2b94a45f2707346d8e66fa" + ], + "markers": "python_version >= '3.7'", + "version": "==0.14.0" + }, + "python-dateutil": { + "hashes": [ + "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86", + "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", + "version": "==2.8.2" + }, + "python-dotenv": { + "hashes": [ + "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca", + "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a" + ], + "index": "pypi", + "version": "==1.0.1" + }, + "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" + ], + "markers": "python_version >= '3.6'", + "version": "==6.0.1" + }, + "pyyaml-env-tag": { + "hashes": [ + "sha256:70092675bda14fdec33b31ba77e7543de9ddc88f2e5b99160396572d11525bdb", + "sha256:af31106dec8a4d68c60207c1886031cbf839b68aa7abccdb19868200532c2069" + ], + "markers": "python_version >= '3.6'", + "version": "==0.1" + }, + "regex": { + "hashes": [ + "sha256:0694219a1d54336fd0445ea382d49d36882415c0134ee1e8332afd1529f0baa5", + "sha256:086dd15e9435b393ae06f96ab69ab2d333f5d65cbe65ca5a3ef0ec9564dfe770", + "sha256:094ba386bb5c01e54e14434d4caabf6583334090865b23ef58e0424a6286d3dc", + "sha256:09da66917262d9481c719599116c7dc0c321ffcec4b1f510c4f8a066f8768105", + "sha256:0ecf44ddf9171cd7566ef1768047f6e66975788258b1c6c6ca78098b95cf9a3d", + "sha256:0fda75704357805eb953a3ee15a2b240694a9a514548cd49b3c5124b4e2ad01b", + "sha256:11a963f8e25ab5c61348d090bf1b07f1953929c13bd2309a0662e9ff680763c9", + "sha256:150c39f5b964e4d7dba46a7962a088fbc91f06e606f023ce57bb347a3b2d4630", + "sha256:1b9d811f72210fa9306aeb88385b8f8bcef0dfbf3873410413c00aa94c56c2b6", + "sha256:1e0eabac536b4cc7f57a5f3d095bfa557860ab912f25965e08fe1545e2ed8b4c", + "sha256:22a86d9fff2009302c440b9d799ef2fe322416d2d58fc124b926aa89365ec482", + "sha256:22f3470f7524b6da61e2020672df2f3063676aff444db1daa283c2ea4ed259d6", + "sha256:263ef5cc10979837f243950637fffb06e8daed7f1ac1e39d5910fd29929e489a", + "sha256:283fc8eed679758de38fe493b7d7d84a198b558942b03f017b1f94dda8efae80", + "sha256:29171aa128da69afdf4bde412d5bedc335f2ca8fcfe4489038577d05f16181e5", + "sha256:298dc6354d414bc921581be85695d18912bea163a8b23cac9a2562bbcd5088b1", + "sha256:2aae8101919e8aa05ecfe6322b278f41ce2994c4a430303c4cd163fef746e04f", + "sha256:2f4e475a80ecbd15896a976aa0b386c5525d0ed34d5c600b6d3ebac0a67c7ddf", + "sha256:34e4af5b27232f68042aa40a91c3b9bb4da0eeb31b7632e0091afc4310afe6cb", + "sha256:37f8e93a81fc5e5bd8db7e10e62dc64261bcd88f8d7e6640aaebe9bc180d9ce2", + "sha256:3a17d3ede18f9cedcbe23d2daa8a2cd6f59fe2bf082c567e43083bba3fb00347", + "sha256:3b1de218d5375cd6ac4b5493e0b9f3df2be331e86520f23382f216c137913d20", + "sha256:43f7cd5754d02a56ae4ebb91b33461dc67be8e3e0153f593c509e21d219c5060", + "sha256:4558410b7a5607a645e9804a3e9dd509af12fb72b9825b13791a37cd417d73a5", + "sha256:4719bb05094d7d8563a450cf8738d2e1061420f79cfcc1fa7f0a44744c4d8f73", + "sha256:4bfc2b16e3ba8850e0e262467275dd4d62f0d045e0e9eda2bc65078c0110a11f", + "sha256:518440c991f514331f4850a63560321f833979d145d7d81186dbe2f19e27ae3d", + "sha256:51f4b32f793812714fd5307222a7f77e739b9bc566dc94a18126aba3b92b98a3", + "sha256:531ac6cf22b53e0696f8e1d56ce2396311254eb806111ddd3922c9d937151dae", + "sha256:5cd05d0f57846d8ba4b71d9c00f6f37d6b97d5e5ef8b3c3840426a475c8f70f4", + "sha256:5dd58946bce44b53b06d94aa95560d0b243eb2fe64227cba50017a8d8b3cd3e2", + "sha256:60080bb3d8617d96f0fb7e19796384cc2467447ef1c491694850ebd3670bc457", + "sha256:636ba0a77de609d6510235b7f0e77ec494d2657108f777e8765efc060094c98c", + "sha256:67d3ccfc590e5e7197750fcb3a2915b416a53e2de847a728cfa60141054123d4", + "sha256:68191f80a9bad283432385961d9efe09d783bcd36ed35a60fb1ff3f1ec2efe87", + "sha256:7502534e55c7c36c0978c91ba6f61703faf7ce733715ca48f499d3dbbd7657e0", + "sha256:7aa47c2e9ea33a4a2a05f40fcd3ea36d73853a2aae7b4feab6fc85f8bf2c9704", + "sha256:7d2af3f6b8419661a0c421584cfe8aaec1c0e435ce7e47ee2a97e344b98f794f", + "sha256:7e316026cc1095f2a3e8cc012822c99f413b702eaa2ca5408a513609488cb62f", + "sha256:88ad44e220e22b63b0f8f81f007e8abbb92874d8ced66f32571ef8beb0643b2b", + "sha256:88d1f7bef20c721359d8675f7d9f8e414ec5003d8f642fdfd8087777ff7f94b5", + "sha256:89723d2112697feaa320c9d351e5f5e7b841e83f8b143dba8e2d2b5f04e10923", + "sha256:8a0ccf52bb37d1a700375a6b395bff5dd15c50acb745f7db30415bae3c2b0715", + "sha256:8c2c19dae8a3eb0ea45a8448356ed561be843b13cbc34b840922ddf565498c1c", + "sha256:905466ad1702ed4acfd67a902af50b8db1feeb9781436372261808df7a2a7bca", + "sha256:9852b76ab558e45b20bf1893b59af64a28bd3820b0c2efc80e0a70a4a3ea51c1", + "sha256:98a2636994f943b871786c9e82bfe7883ecdaba2ef5df54e1450fa9869d1f756", + "sha256:9aa1a67bbf0f957bbe096375887b2505f5d8ae16bf04488e8b0f334c36e31360", + "sha256:9eda5f7a50141291beda3edd00abc2d4a5b16c29c92daf8d5bd76934150f3edc", + "sha256:a6d1047952c0b8104a1d371f88f4ab62e6275567d4458c1e26e9627ad489b445", + "sha256:a9b6d73353f777630626f403b0652055ebfe8ff142a44ec2cf18ae470395766e", + "sha256:a9cc99d6946d750eb75827cb53c4371b8b0fe89c733a94b1573c9dd16ea6c9e4", + "sha256:ad83e7545b4ab69216cef4cc47e344d19622e28aabec61574b20257c65466d6a", + "sha256:b014333bd0217ad3d54c143de9d4b9a3ca1c5a29a6d0d554952ea071cff0f1f8", + "sha256:b43523d7bc2abd757119dbfb38af91b5735eea45537ec6ec3a5ec3f9562a1c53", + "sha256:b521dcecebc5b978b447f0f69b5b7f3840eac454862270406a39837ffae4e697", + "sha256:b77e27b79448e34c2c51c09836033056a0547aa360c45eeeb67803da7b0eedaf", + "sha256:b7a635871143661feccce3979e1727c4e094f2bdfd3ec4b90dfd4f16f571a87a", + "sha256:b7fca9205b59c1a3d5031f7e64ed627a1074730a51c2a80e97653e3e9fa0d415", + "sha256:ba1b30765a55acf15dce3f364e4928b80858fa8f979ad41f862358939bdd1f2f", + "sha256:ba99d8077424501b9616b43a2d208095746fb1284fc5ba490139651f971d39d9", + "sha256:c25a8ad70e716f96e13a637802813f65d8a6760ef48672aa3502f4c24ea8b400", + "sha256:c3c4a78615b7762740531c27cf46e2f388d8d727d0c0c739e72048beb26c8a9d", + "sha256:c40281f7d70baf6e0db0c2f7472b31609f5bc2748fe7275ea65a0b4601d9b392", + "sha256:c7ad32824b7f02bb3c9f80306d405a1d9b7bb89362d68b3c5a9be53836caebdb", + "sha256:cb3fe77aec8f1995611f966d0c656fdce398317f850d0e6e7aebdfe61f40e1cd", + "sha256:cc038b2d8b1470364b1888a98fd22d616fba2b6309c5b5f181ad4483e0017861", + "sha256:cc37b9aeebab425f11f27e5e9e6cf580be7206c6582a64467a14dda211abc232", + "sha256:cc6bb9aa69aacf0f6032c307da718f61a40cf970849e471254e0e91c56ffca95", + "sha256:d126361607b33c4eb7b36debc173bf25d7805847346dd4d99b5499e1fef52bc7", + "sha256:d15b274f9e15b1a0b7a45d2ac86d1f634d983ca40d6b886721626c47a400bf39", + "sha256:d166eafc19f4718df38887b2bbe1467a4f74a9830e8605089ea7a30dd4da8887", + "sha256:d498eea3f581fbe1b34b59c697512a8baef88212f92e4c7830fcc1499f5b45a5", + "sha256:d6f7e255e5fa94642a0724e35406e6cb7001c09d476ab5fce002f652b36d0c39", + "sha256:d78bd484930c1da2b9679290a41cdb25cc127d783768a0369d6b449e72f88beb", + "sha256:d865984b3f71f6d0af64d0d88f5733521698f6c16f445bb09ce746c92c97c586", + "sha256:d902a43085a308cef32c0d3aea962524b725403fd9373dea18110904003bac97", + "sha256:d94a1db462d5690ebf6ae86d11c5e420042b9898af5dcf278bd97d6bda065423", + "sha256:da695d75ac97cb1cd725adac136d25ca687da4536154cdc2815f576e4da11c69", + "sha256:db2a0b1857f18b11e3b0e54ddfefc96af46b0896fb678c85f63fb8c37518b3e7", + "sha256:df26481f0c7a3f8739fecb3e81bc9da3fcfae34d6c094563b9d4670b047312e1", + "sha256:e14b73607d6231f3cc4622809c196b540a6a44e903bcfad940779c80dffa7be7", + "sha256:e2610e9406d3b0073636a3a2e80db05a02f0c3169b5632022b4e81c0364bcda5", + "sha256:e692296c4cc2873967771345a876bcfc1c547e8dd695c6b89342488b0ea55cd8", + "sha256:e693e233ac92ba83a87024e1d32b5f9ab15ca55ddd916d878146f4e3406b5c91", + "sha256:e81469f7d01efed9b53740aedd26085f20d49da65f9c1f41e822a33992cb1590", + "sha256:e8c7e08bb566de4faaf11984af13f6bcf6a08f327b13631d41d62592681d24fe", + "sha256:ed19b3a05ae0c97dd8f75a5d8f21f7723a8c33bbc555da6bbe1f96c470139d3c", + "sha256:efb2d82f33b2212898f1659fb1c2e9ac30493ac41e4d53123da374c3b5541e64", + "sha256:f44dd4d68697559d007462b0a3a1d9acd61d97072b71f6d1968daef26bc744bd", + "sha256:f72cbae7f6b01591f90814250e636065850c5926751af02bb48da94dfced7baa", + "sha256:f7bc09bc9c29ebead055bcba136a67378f03d66bf359e87d0f7c759d6d4ffa31", + "sha256:ff100b203092af77d1a5a7abe085b3506b7eaaf9abf65b73b7d6905b6cb76988" + ], + "markers": "python_version >= '3.7'", + "version": "==2023.12.25" + }, + "requests": { + "hashes": [ + "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f", + "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1" + ], + "index": "pypi", + "version": "==2.31.0" + }, + "six": { + "hashes": [ + "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", + "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", + "version": "==1.16.0" + }, + "soupsieve": { + "hashes": [ + "sha256:5663d5a7b3bfaeee0bc4372e7fc48f9cff4940b3eec54a6451cc5299f1097690", + "sha256:eaa337ff55a1579b6549dc679565eac1e3d000563bcb1c8ab0d0fefbc0c2cdc7" + ], + "markers": "python_version >= '3.8'", + "version": "==2.5" + }, + "tinycss2": { + "hashes": [ + "sha256:2b80a96d41e7c3914b8cda8bc7f705a4d9c49275616e886103dd839dfc847847", + "sha256:8cff3a8f066c2ec677c06dbc7b45619804a6938478d9d73c284b29d14ecb0627" + ], + "markers": "python_version >= '3.7'", + "version": "==1.2.1" + }, + "urllib3": { + "hashes": [ + "sha256:55901e917a5896a349ff771be919f8bd99aff50b79fe58fec595eb37bbc56bb3", + "sha256:df7aa8afb0148fa78488e7899b2c59b5f4ffcfa82e6c54ccb9dd37c1d7b52d54" + ], + "markers": "python_version >= '3.8'", + "version": "==2.1.0" + }, + "watchdog": { + "hashes": [ + "sha256:0e06ab8858a76e1219e68c7573dfeba9dd1c0219476c5a44d5333b01d7e1743a", + "sha256:13bbbb462ee42ec3c5723e1205be8ced776f05b100e4737518c67c8325cf6100", + "sha256:233b5817932685d39a7896b1090353fc8efc1ef99c9c054e46c8002561252fb8", + "sha256:25f70b4aa53bd743729c7475d7ec41093a580528b100e9a8c5b5efe8899592fc", + "sha256:2b57a1e730af3156d13b7fdddfc23dea6487fceca29fc75c5a868beed29177ae", + "sha256:336adfc6f5cc4e037d52db31194f7581ff744b67382eb6021c868322e32eef41", + "sha256:3aa7f6a12e831ddfe78cdd4f8996af9cf334fd6346531b16cec61c3b3c0d8da0", + "sha256:3ed7c71a9dccfe838c2f0b6314ed0d9b22e77d268c67e015450a29036a81f60f", + "sha256:4c9956d27be0bb08fc5f30d9d0179a855436e655f046d288e2bcc11adfae893c", + "sha256:4d98a320595da7a7c5a18fc48cb633c2e73cda78f93cac2ef42d42bf609a33f9", + "sha256:4f94069eb16657d2c6faada4624c39464f65c05606af50bb7902e036e3219be3", + "sha256:5113334cf8cf0ac8cd45e1f8309a603291b614191c9add34d33075727a967709", + "sha256:51f90f73b4697bac9c9a78394c3acbbd331ccd3655c11be1a15ae6fe289a8c83", + "sha256:5d9f3a10e02d7371cd929b5d8f11e87d4bad890212ed3901f9b4d68767bee759", + "sha256:7ade88d0d778b1b222adebcc0927428f883db07017618a5e684fd03b83342bd9", + "sha256:7c5f84b5194c24dd573fa6472685b2a27cc5a17fe5f7b6fd40345378ca6812e3", + "sha256:7e447d172af52ad204d19982739aa2346245cc5ba6f579d16dac4bfec226d2e7", + "sha256:8ae9cda41fa114e28faf86cb137d751a17ffd0316d1c34ccf2235e8a84365c7f", + "sha256:8f3ceecd20d71067c7fd4c9e832d4e22584318983cabc013dbf3f70ea95de346", + "sha256:9fac43a7466eb73e64a9940ac9ed6369baa39b3bf221ae23493a9ec4d0022674", + "sha256:a70a8dcde91be523c35b2bf96196edc5730edb347e374c7de7cd20c43ed95397", + "sha256:adfdeab2da79ea2f76f87eb42a3ab1966a5313e5a69a0213a3cc06ef692b0e96", + "sha256:ba07e92756c97e3aca0912b5cbc4e5ad802f4557212788e72a72a47ff376950d", + "sha256:c07253088265c363d1ddf4b3cdb808d59a0468ecd017770ed716991620b8f77a", + "sha256:c9d8c8ec7efb887333cf71e328e39cffbf771d8f8f95d308ea4125bf5f90ba64", + "sha256:d00e6be486affb5781468457b21a6cbe848c33ef43f9ea4a73b4882e5f188a44", + "sha256:d429c2430c93b7903914e4db9a966c7f2b068dd2ebdd2fa9b9ce094c7d459f33" + ], + "markers": "python_version >= '3.7'", + "version": "==3.0.0" + }, + "weasyprint": { + "hashes": [ + "sha256:0c0cdd617a78699262b80026e67fa1692e3802cfa966395436eeaf6f787dd126", + "sha256:3e98eedcc1c5a14cb310c293c6d59a479f59a13f0d705ff07106482827fa5705" + ], + "markers": "python_version >= '3.7'", + "version": "==60.2" + }, + "webencodings": { + "hashes": [ + "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78", + "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923" + ], + "version": "==0.5.1" + }, + "zopfli": { + "hashes": [ + "sha256:0574372283befa5af98fb31407e1fe6822f2f9c437ef69e7fa260e49022d8a65", + "sha256:082f030b2b7d6d4597ac517816e499c63b92130aa8f4f74a3788ebaa5770f974", + "sha256:08d105a49576a9e629f53a710f0009c4bf0a1d8a3239a74e41d0944f26e28a61", + "sha256:09ad5f8d7e0fe1975ca6d9fd5ad61c74233ae277982d3bc8814b599bbeb92f44", + "sha256:0fbb6e7fc0da56835167e3c83a45b28e99ba14b671ecb8e51100ad03dfffc3d0", + "sha256:13d151d5c83980f384439c87a5511853890182c05d93444f3cb05e5ceed37d82", + "sha256:1c5fd29730024f5fb0e2623e3853ca422bd3cf57042389c8e0e771dc47f88084", + "sha256:1f25f1bb6440ed90a1d458772fa6ce53632f5fb61e435b12ae6b9b39af98d758", + "sha256:2073b07c3ec4fcbc895bb02565a90f9f31373233979f6be398e82eacbd1105f3", + "sha256:22b1cfc398a87754730f7e268693c8eb480cb688fd645648fda85614a8b1c08c", + "sha256:2770cf6b88e9985c79b90fd6d4c15d8dab0caa37c1c3b17773e61ce857eab586", + "sha256:27f2b58050f84fa059db7a6ec17d98b388c18f9783551e5f97605f790f25e155", + "sha256:2da6f30632cefda8ebe032fdcb69cf062f5a6435af9d32de82ccef320e0261f5", + "sha256:31c467a300ba46f55aa0ea958ea388e350eefd039cf15764bf4cd737d5eeb8a6", + "sha256:39d8a73bee07cf7f2c73e08508bf788bfdf28a527da353b5d3e2a0ee4aaf770c", + "sha256:3e4675ca4c7b1215b8a53cec1831cbdb6914f91ea2f183817a06fc7b38e27642", + "sha256:40665bf0bacc8b82652a1af4016648dd69f896afa59fc481c1d19a222aa746ea", + "sha256:40b830244e6458ef982b4a5ebb0f228986d481408bae557a95eeece2c5ede4e6", + "sha256:52438999888715a378fc6fe1477ab7813e9e9b58a27a38d2ad7be0e396b1ab2e", + "sha256:57f93802e5ddb20647747ee4039a2e18a26e91bac4c41d3d75a2b2c97f270549", + "sha256:5e52aaab3a93470cf0ff2bb2135a8628dda7b70f675c46f35b6a1b30e8e482f4", + "sha256:6020a3533c6c7be09db9e59c2a8f3f894bf5d8e95cc01890d82114c923317c57", + "sha256:61a2fcc624e8b038d4fca84ba927dc3f31df53a7284692d46aa44d16fb3f47b2", + "sha256:61abe5f11400f9c6b22be578091e28dfb9f1a61efaaeaa2da66138b03ee93072", + "sha256:6225bbc33c4f803cdc1e71e3028af96dd0e1ed3cf061780d1bf05648df616a05", + "sha256:711d4fde9cb99e1a9158978e9d1624a37cdd170ff057f6340059514fcf38e808", + "sha256:72349c78da402e6784bd9c5f4aff5cc7017bd969016ec07b656722f7f29fc975", + "sha256:7463b42a2cee33f0a018bf8f1304da2379d6cb8111aa4e04d8f8590d0f1099e1", + "sha256:7599ce108386d91a402969cba4f17247e33a594b21cbd662e008414ccb0b4cf7", + "sha256:7769f6ca73f37dff92159127bd25b0cc7d81d3feb819d355dc7ac01ad05c673d", + "sha256:78022777139ac973286219e9e085d9496fb6c935502d93a52bd1bed01dfc2002", + "sha256:7bc89b71d1c4677f708cc162f40a4560f78f5f4c6aa6d884b423df7d38e8ba0b", + "sha256:7ddcbc258bb5c07ebb7f6ee64c46d4e35c39c6abba2b3dfa72c0ea4daf9e65fc", + "sha256:7ebb4e1b0f102d431830151041777c55700d12afd1e5adb5bcbce72037c1a10e", + "sha256:81d61eba5a8e221b297a1dd27f1dae2785a14a5524cc1e144da53705cf90d5c4", + "sha256:8293062567917201609b28b865289d5ddee55030c779fa9264caae4cc2e00fb3", + "sha256:84321886cf3e80e086e0f6f7b765975343aafa61165315bb8db514d0bec2d887", + "sha256:92ca61eaa1df774908c173683e23c512189bf791a7ebb49fac61324658cff490", + "sha256:975d45745cf6c3e3b61127e0140dcf145fa515f2021f669bd82768937b7bb1fb", + "sha256:978395a4ce5cc46db29a36cdb80549b564dc7706237abaca5aac328dd5842f65", + "sha256:97d2f993142fed4f9c11c1766eb53409efe7298c755cf4599c171bfedcbaddae", + "sha256:9dcf7af42c11b3cf5d3fbf665799e10f54f66caea2020fe304602df83b9a1a69", + "sha256:ad2a98890045d13b0cdc93c1637990c211dc877493469afc61a097a00a70cf22", + "sha256:ae890df6e5f1e8fa0697cafd848826decce0ac53e54e5a018fd97775e3a354c0", + "sha256:b30a922b9d73f22da2b589b35e594dcc6d144eb38ad890c542f2b92902ba9892", + "sha256:c1afe5ba0d957e462afbd3da116ac1a2a6d23e8a94436a95b692c5c324694a16", + "sha256:c3c61787a90439cf68f751b2a1ab789b0805876c0cd9b58398adc212d1eeace5", + "sha256:c6555293e42e7a9154940bb18613de2abce21a855780baff8a6c372e395c59b3", + "sha256:ca9a6df3d11c2f8f0356c141523c4914a2850dd39fc213d968c0272db635eea9", + "sha256:d0a8e556916088fadb098ddb6eed034d5c2df3b8fba7f2488e87e8c224002eca", + "sha256:d40373db61883f6fc8b7040c9196a16f737e3063632afd15e8b3f25e871a30e8", + "sha256:dbc9841bedd736041eb5e6982cd92da93bee145745f5422f3795f6f258cdc6ef", + "sha256:dc59299eda2aaf57f0ee5c4b42ada0b80e3dc4c09c5bdda8ee9ae5cf93fafa9e", + "sha256:deffa15253a43a597e8ebf82ca1908bd70b3bf899da163b017d49ddd5e12732a", + "sha256:e4068d4d35b2e63898d22e1b7777d986b8f5d61fe83a77973730ce9cff1b4ba1", + "sha256:e5f62ca9a947f09f531c721e2a3f2e0094523436b8eb5df18d71245c1924f89a", + "sha256:eef08c02295bb99c7fdca380c52e5454fa1c08025fb0bea2c7ae6c0e1e9c034b", + "sha256:f07997453e7777e19ef0a2445cc1b90e1bb90c623dd77554325932dea6350fee", + "sha256:f48de4818c10c539fdd01276512043ae4ae738e0301e9cace1dd38f4bcffad6a", + "sha256:f69b161b4d49e256ab285c6c6ee1cf217fda864a9b175d24fa0a0b8c2de9ff13", + "sha256:ff86a2cd6b9864027861a129d6d73231b6d463f0d364ca0fdca4492390357cba" + ], + "version": "==0.2.3" + } + }, + "develop": {} +} diff --git a/dbrepo-data-service/README.md b/dbrepo-data-service/README.md index 0441a17305f7f085082c445d8f77825c721a41be..dfea03bc6bc415d9b4792853cff16ff1372fe377 100644 --- a/dbrepo-data-service/README.md +++ b/dbrepo-data-service/README.md @@ -1,6 +1,31 @@ # Data Service -## Actuator +## Test + +Run all unit and integration tests and create an HTML+TXT coverage report located in the `report` module: + +```bash +mvn -pl rest-service clean test verify +``` + +Or run only tests +in [`DatabaseServiceIntegrationTest.java`](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/blob/master/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/DatabaseServiceIntegrationTest.java): + +```bash +mvn -pl rest-service -Dtest="DatabaseServiceIntegrationTest" clean test +``` + +## Run + +Start the Metadata Database, Data Database, Broker Service before and then run the Data Service: + +```bash +mvn -pl rest-service clean spring-boot:run -Dspring-boot.run.profiles=local +``` + +### Endpoints + +#### Actuator - Info: http://localhost:9093/actuator/info - Health: http://localhost:9093/actuator/health @@ -8,17 +33,10 @@ - Liveness: http://localhost:9093/actuator/health/liveness - Prometheus: http://localhost:9093/actuator/prometheus -## Swagger UI Endpoints +#### Swagger UI - Swagger UI: http://localhost:9093/swagger-ui/index.html -## OpenAPI Endpoints - -- OpenAPI v3 as .yaml: http://localhost:9093/v3/api-docs.yaml - -## Build +#### OpenAPI -```shell -mvn -f ../dbrepo-metadata-service/pom.xml clean install -DskipTests -mvn clean package -DskipTests -``` \ No newline at end of file +- OpenAPI v3 as .yaml: http://localhost:9093/v3/api-docs.yaml \ No newline at end of file diff --git a/dbrepo-data-service/pom.xml b/dbrepo-data-service/pom.xml index 22dcf3329572f60d0efbf921276414945902e8ba..6b9556bf5f2de2d20b6680f13913333bd1350aea 100644 --- a/dbrepo-data-service/pom.xml +++ b/dbrepo-data-service/pom.xml @@ -13,7 +13,7 @@ <name>dbrepo-data-service</name> <version>1.4.1</version> - <description>This service is responsible for the database-specific CRUD operations.</description> + <description>Service that manages the data</description> <url>https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/</url> <developers> @@ -60,7 +60,7 @@ <opencsv.version>5.7.1</opencsv.version> <super-csv.version>2.4.0</super-csv.version> <jsql.version>4.6</jsql.version> - <springdoc-openapi.version>2.1.0</springdoc-openapi.version> + <springdoc-openapi.version>2.3.0</springdoc-openapi.version> <hsqldb.version>2.7.2</hsqldb.version> <testcontainers.version>1.19.1</testcontainers.version> <opensearch-testcontainer.version>2.0.0</opensearch-testcontainer.version> @@ -195,12 +195,7 @@ <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> - <exclusions> - <exclusion> - <groupId>org.junit.jupiter</groupId> - <artifactId>junit-vintage-engine</artifactId> - </exclusion> - </exclusions> + <scope>test</scope> </dependency> <dependency> <groupId>com.h2database</groupId> diff --git a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/config/SwaggerConfig.java b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/config/SwaggerConfig.java index f7b33979a78946d23cfea809a49a20f2d75bdb76..56ea660541925aa401a967700764b431c2b41fab 100644 --- a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/config/SwaggerConfig.java +++ b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/config/SwaggerConfig.java @@ -7,6 +7,7 @@ import io.swagger.v3.oas.models.info.Info; import io.swagger.v3.oas.models.info.License; import io.swagger.v3.oas.models.servers.Server; import org.springdoc.core.models.GroupedOpenApi; +import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -15,6 +16,9 @@ import java.util.List; @Configuration public class SwaggerConfig { + @Value("${server.port}") + private Integer port; + @Bean public OpenAPI springShopOpenAPI() { return new OpenAPI() @@ -32,10 +36,10 @@ public class SwaggerConfig { .description("Sourcecode Documentation") .url("https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services")) .servers(List.of(new Server() - .description("Generated server url") - .url("http://localhost:9093"), + .description("Development instance") + .url("http://localhost:" + port), new Server() - .description("Sandbox") + .description("Staging instance") .url("https://test.dbrepo.tuwien.ac.at"))); } diff --git a/dbrepo-metadata-service/README.md b/dbrepo-metadata-service/README.md index e550dc8d6b1f919d5764b25b435b4d8a2c436dd7..f7abaeaab0a521fd611fa4eedad1b0d50c975f9f 100644 --- a/dbrepo-metadata-service/README.md +++ b/dbrepo-metadata-service/README.md @@ -1,4 +1,4 @@ -# Semantics Service +# Metadata Service ## Test @@ -29,6 +29,8 @@ mvn -pl rest-service clean spring-boot:run -Dspring-boot.run.profiles=local - Info: http://localhost:9099/actuator/info - Health: http://localhost:9099/actuator/health + - Readiness: http://localhost:9099/actuator/health/readiness + - Liveness: http://localhost:9099/actuator/health/liveness - Prometheus: http://localhost:9099/actuator/prometheus #### Swagger UI diff --git a/dbrepo-metadata-service/pom.xml b/dbrepo-metadata-service/pom.xml index 49de9e8df13110401f3fe4c3e459d4caa9748e99..22f9a858fb6e21977094852d65ff1557c77495af 100644 --- a/dbrepo-metadata-service/pom.xml +++ b/dbrepo-metadata-service/pom.xml @@ -75,7 +75,7 @@ <super-csv.version>2.4.0</super-csv.version> <jsql-parser.version>4.6</jsql-parser.version> <keycloak.version>21.0.2</keycloak.version> - <springdoc-openapi.version>2.1.0</springdoc-openapi.version> + <springdoc-openapi.version>2.3.0</springdoc-openapi.version> <testcontainers.version>1.19.1</testcontainers.version> <opensearch-testcontainer.version>2.0.0</opensearch-testcontainer.version> <keycloak-testcontainer.version>3.2.0</keycloak-testcontainer.version> diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/config/SwaggerConfig.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/config/SwaggerConfig.java index 8aa287f9fd5c51548aec0ca20562cd07a84d335d..c3e047da3afba5c60eaf8d5e7fe93311d2db782a 100644 --- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/config/SwaggerConfig.java +++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/config/SwaggerConfig.java @@ -7,6 +7,7 @@ import io.swagger.v3.oas.models.info.Info; import io.swagger.v3.oas.models.info.License; import io.swagger.v3.oas.models.servers.Server; import org.springdoc.core.models.GroupedOpenApi; +import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -15,6 +16,9 @@ import java.util.List; @Configuration public class SwaggerConfig { + @Value("${server.port}") + private Integer port; + @Bean public OpenAPI springShopOpenAPI() { return new OpenAPI() @@ -32,10 +36,10 @@ public class SwaggerConfig { .description("Sourcecode Documentation") .url("https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services")) .servers(List.of(new Server() - .description("Generated server url") - .url("http://localhost:9099"), + .description("Development instance") + .url("http://localhost:" + port), new Server() - .description("Sandbox") + .description("Staging instance") .url("https://test.dbrepo.tuwien.ac.at"))); } 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 054bc7cfa9e29eb819ec0329d6c4ba23aa559470..0d79f8288aa1e0eb1a330bb52f4070dd0b668b48 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 @@ -49,7 +49,7 @@ public class AccessEndpoint { @Transactional @Observed(name = "dbr_access_give") @PreAuthorize("hasAuthority('create-database-access')") - @Operation(summary = "Give access to some database", security = @SecurityRequirement(name = "bearerAuth")) + @Operation(summary = "Give access to some database", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")}) @ApiResponses(value = { @ApiResponse(responseCode = "202", description = "Granting access succeeded", @@ -98,7 +98,7 @@ public class AccessEndpoint { @Transactional @Observed(name = "dbr_access_modify") @PreAuthorize("hasAuthority('update-database-access')") - @Operation(summary = "Modify access to some database", security = @SecurityRequirement(name = "bearerAuth")) + @Operation(summary = "Modify access to some database", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")}) @ApiResponses(value = { @ApiResponse(responseCode = "202", description = "Modify access succeeded", @@ -136,7 +136,7 @@ public class AccessEndpoint { @Transactional @Observed(name = "dbr_access_check") @PreAuthorize("hasAuthority('check-database-access')") - @Operation(summary = "Check access to some database", security = @SecurityRequirement(name = "bearerAuth")) + @Operation(summary = "Check access to some database", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")}) @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Found database access", @@ -168,7 +168,7 @@ public class AccessEndpoint { @Transactional @Observed(name = "dbr_access_delete") @PreAuthorize("hasAuthority('delete-database-access')") - @Operation(summary = "Revoke access to some database", security = @SecurityRequirement(name = "bearerAuth")) + @Operation(summary = "Revoke access to some database", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")}) @ApiResponses(value = { @ApiResponse(responseCode = "202", description = "Revoked access successfully", 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 c0e01632f35a48bda6b0be6534d84b0a054b6416..4923e6a859cd0397ff72e81fe837bc59625fea4d 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 @@ -77,7 +77,7 @@ public class ContainerEndpoint { @Transactional @Observed(name = "dbr_container_create") @PreAuthorize("hasAuthority('create-container')") - @Operation(summary = "Create container", security = @SecurityRequirement(name = "bearerAuth")) + @Operation(summary = "Create container", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")}) @ApiResponses(value = { @ApiResponse(responseCode = "201", description = "Created a new container", @@ -136,7 +136,7 @@ public class ContainerEndpoint { @Transactional @Observed(name = "dbr_container_delete") @PreAuthorize("hasAuthority('delete-container')") - @Operation(summary = "Delete some container", security = @SecurityRequirement(name = "bearerAuth")) + @Operation(summary = "Delete some container", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")}) @ApiResponses(value = { @ApiResponse(responseCode = "202", description = "Deleted container successfully"), 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 beec5ad35112142480210e50c394df248cff2f29..5f6aad756dd13aef9939501a78e17c5cf4635072 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 @@ -141,7 +141,7 @@ public class DatabaseEndpoint { @Transactional(rollbackFor = Exception.class) @PreAuthorize("hasAuthority('create-database')") @Observed(name = "dbr_database_create") - @Operation(summary = "Create database", security = @SecurityRequirement(name = "bearerAuth")) + @Operation(summary = "Create database", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")}) @ApiResponses(value = { @ApiResponse(responseCode = "201", description = "Created a new database", @@ -196,7 +196,7 @@ public class DatabaseEndpoint { @Transactional @PreAuthorize("hasAuthority('modify-database-visibility')") @Observed(name = "dbr_database_visibility") - @Operation(summary = "Update database", security = @SecurityRequirement(name = "bearerAuth")) + @Operation(summary = "Update database", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")}) @ApiResponses(value = { @ApiResponse(responseCode = "202", description = "Visibility modified successfully", @@ -234,7 +234,7 @@ public class DatabaseEndpoint { @Transactional @PreAuthorize("hasAuthority('modify-database-owner')") @Observed(name = "dbr_database_transfer") - @Operation(summary = "Transfer database", security = @SecurityRequirement(name = "bearerAuth")) + @Operation(summary = "Transfer database", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")}) @ApiResponses(value = { @ApiResponse(responseCode = "202", description = "Transfer of ownership was successful", @@ -272,7 +272,7 @@ public class DatabaseEndpoint { @GetMapping("/{id}") @Transactional(readOnly = true) @Observed(name = "dbr_database_find") - @Operation(summary = "Find some database", security = @SecurityRequirement(name = "bearerAuth")) + @Operation(summary = "Find some database", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")}) @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Database found successfully", diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ExportEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ExportEndpoint.java index 5a994cdae9f2afd193aa3e42318144e068a86587..184869eddc6edf41c59bc201e29d62daed81dbad 100644 --- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ExportEndpoint.java +++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ExportEndpoint.java @@ -46,7 +46,7 @@ public class ExportEndpoint { @GetMapping @Transactional(readOnly = true) @Observed(name = "dbr_table_export") - @Operation(summary = "Export table", security = @SecurityRequirement(name = "bearerAuth")) + @Operation(summary = "Export table", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")}) @ApiResponses(value = { @ApiResponse(responseCode = "201", description = "Created identifier", diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/IdentifierEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/IdentifierEndpoint.java index 518b68180c8c5861ce744808fa6a858efef5c545..0af00f4c0e9b9a34779e7ed22a7e66b21ade475a 100644 --- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/IdentifierEndpoint.java +++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/IdentifierEndpoint.java @@ -103,7 +103,7 @@ public class IdentifierEndpoint { @Transactional @Observed(name = "dbr_identifier_create") @PreAuthorize("hasAuthority('create-identifier') or hasAuthority('create-foreign-identifier')") - @Operation(summary = "Create identifier", security = @SecurityRequirement(name = "bearerAuth")) + @Operation(summary = "Create identifier", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")}) @ApiResponses(value = { @ApiResponse(responseCode = "201", description = "Created identifier", diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ImageEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ImageEndpoint.java index 1ac1988a2aca03557e63d19c884001bd8da06476..2544d36f15b975e1c26356745e59760ada1a3cea 100644 --- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ImageEndpoint.java +++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ImageEndpoint.java @@ -75,7 +75,7 @@ public class ImageEndpoint { @Transactional @Observed(name = "dbr_image_create") @PreAuthorize("hasAuthority('create-image')") - @Operation(summary = "Create image", security = @SecurityRequirement(name = "bearerAuth")) + @Operation(summary = "Create image", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")}) @ApiResponses(value = { @ApiResponse(responseCode = "201", description = "Created image", @@ -137,7 +137,7 @@ public class ImageEndpoint { @Transactional @Observed(name = "dbr_image_update") @PreAuthorize("hasAuthority('modify-image')") - @Operation(summary = "Update some image", security = @SecurityRequirement(name = "bearerAuth")) + @Operation(summary = "Update some image", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")}) @ApiResponses(value = { @ApiResponse(responseCode = "202", description = "Updated image successfully", @@ -166,7 +166,7 @@ public class ImageEndpoint { @Transactional @Observed(name = "dbr_image_delete") @PreAuthorize("hasAuthority('delete-image')") - @Operation(summary = "Delete some image", security = @SecurityRequirement(name = "bearerAuth")) + @Operation(summary = "Delete some image", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")}) @ApiResponses(value = { @ApiResponse(responseCode = "202", description = "Deleted image successfully", diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/OntologyEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/OntologyEndpoint.java index b03d183707f2767c8e9b2c7929424e4198aa3f4f..9060aacb15e8f55582d9604dfb0858ba29b0880e 100644 --- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/OntologyEndpoint.java +++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/OntologyEndpoint.java @@ -90,7 +90,7 @@ public class OntologyEndpoint { @PostMapping @PreAuthorize("hasAuthority('create-ontology')") @Observed(name = "dbr_ontologies_create") - @Operation(summary = "Register a new ontology", security = @SecurityRequirement(name = "bearerAuth")) + @Operation(summary = "Register a new ontology", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")}) @ApiResponses(value = { @ApiResponse(responseCode = "201", description = "Registered ontology successfully", @@ -110,7 +110,7 @@ public class OntologyEndpoint { @PutMapping("/{id}") @PreAuthorize("hasAuthority('update-ontology')") @Observed(name = "dbr_ontologies_update") - @Operation(summary = "Update an ontology", security = @SecurityRequirement(name = "bearerAuth")) + @Operation(summary = "Update an ontology", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")}) @ApiResponses(value = { @ApiResponse(responseCode = "202", description = "Updated ontology successfully", @@ -136,7 +136,7 @@ public class OntologyEndpoint { @DeleteMapping("/{id}") @PreAuthorize("hasAuthority('delete-ontology')") @Observed(name = "dbr_ontologies_delete") - @Operation(summary = "Delete an ontology", security = @SecurityRequirement(name = "bearerAuth")) + @Operation(summary = "Delete an ontology", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")}) @ApiResponses(value = { @ApiResponse(responseCode = "202", description = "Deleted ontology successfully", @@ -158,7 +158,7 @@ public class OntologyEndpoint { @GetMapping("/{id}/entity") @PreAuthorize("hasAuthority('execute-semantic-query')") @Observed(name = "dbr_ontologies_entities_find") - @Operation(summary = "Find entities", security = @SecurityRequirement(name = "bearerAuth")) + @Operation(summary = "Find entities", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")}) @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Found entities", diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/PersistenceEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/PersistenceEndpoint.java index a39ecc85a5c7425432519b921551dce6ff17f157..8b588ab3e22dac539b31e175a3049f44a93e9a79 100644 --- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/PersistenceEndpoint.java +++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/PersistenceEndpoint.java @@ -163,7 +163,7 @@ public class PersistenceEndpoint { @Transactional @Observed(name = "dbr_pid_delete") @PreAuthorize("hasAuthority('delete-identifier')") - @Operation(summary = "Delete some identifier", security = @SecurityRequirement(name = "bearerAuth")) + @Operation(summary = "Delete some identifier", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")}) @ApiResponses(value = { @ApiResponse(responseCode = "202", description = "Deleted identifier"), diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/QueryEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/QueryEndpoint.java index bcbcab6a3864280f68c5fe3bbc54adb07b5e4000..f46afa62cc9ec15f135f939f5e2436acb2fb313e 100644 --- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/QueryEndpoint.java +++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/QueryEndpoint.java @@ -57,7 +57,7 @@ public class QueryEndpoint { @Transactional(readOnly = true) @Observed(name = "dbr_query_execute") @PreAuthorize("hasAuthority('execute-query')") - @Operation(summary = "Execute query", security = @SecurityRequirement(name = "bearerAuth")) + @Operation(summary = "Execute query", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")}) @ApiResponses(value = { @ApiResponse(responseCode = "202", description = "Executed query", @@ -121,7 +121,7 @@ public class QueryEndpoint { @GetMapping("/{queryId}/data") @Transactional(readOnly = true) @Observed(name = "dbr_query_reexecute") - @Operation(summary = "Re-execute some query", security = @SecurityRequirement(name = "bearerAuth")) + @Operation(summary = "Re-execute some query", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")}) @ApiResponses(value = { @ApiResponse(responseCode = "202", description = "Executed query", @@ -181,7 +181,7 @@ public class QueryEndpoint { @GetMapping("/{queryId}/data/count") @Transactional(readOnly = true) @Observed(name = "dbr_query_reexecute_count") - @Operation(summary = "Re-execute some query", security = @SecurityRequirement(name = "bearerAuth")) + @Operation(summary = "Re-execute some query", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")}) @ApiResponses(value = { @ApiResponse(responseCode = "202", description = "Executed query", @@ -228,7 +228,7 @@ public class QueryEndpoint { @GetMapping("/{queryId}/export") @Transactional(readOnly = true) @Observed(name = "dbr_query_export") - @Operation(summary = "Exports some query", security = @SecurityRequirement(name = "bearerAuth")) + @Operation(summary = "Exports some query", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")}) @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Executed query"), diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/SemanticsEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/SemanticsEndpoint.java index 1fb5b883e6481cfbf5eacc56eb1281c82f271cfc..46c418be905b9d786cc6a08143ca2c45c8e5604e 100644 --- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/SemanticsEndpoint.java +++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/SemanticsEndpoint.java @@ -93,7 +93,7 @@ public class SemanticsEndpoint { @Transactional(readOnly = true) @PreAuthorize("hasAuthority('table-semantic-analyse')") @Observed(name = "dbr_semantic_table_analyse") - @Operation(summary = "Suggest table semantics", security = @SecurityRequirement(name = "bearerAuth")) + @Operation(summary = "Suggest table semantics", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")}) @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Suggested table semantics successfully", @@ -130,7 +130,7 @@ public class SemanticsEndpoint { @Transactional(readOnly = true) @PreAuthorize("hasAuthority('table-semantic-analyse')") @Observed(name = "dbr_semantic_column_analyse") - @Operation(summary = "Suggest table column semantics", security = @SecurityRequirement(name = "bearerAuth")) + @Operation(summary = "Suggest table column semantics", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")}) @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Suggested table column semantics successfully", diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/StoreEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/StoreEndpoint.java index 1ff758a309f0b54c2f5f48005dc525d6571b698e..d96fea7342c1be5083194dcf6f9e93b4ea5c50a2 100644 --- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/StoreEndpoint.java +++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/StoreEndpoint.java @@ -74,7 +74,7 @@ public class StoreEndpoint { @GetMapping @Transactional(readOnly = true) @Observed(name = "dbr_queries_findall") - @Operation(summary = "Find queries", security = @SecurityRequirement(name = "bearerAuth")) + @Operation(summary = "Find queries", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")}) @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "List queries", @@ -151,7 +151,7 @@ public class StoreEndpoint { @GetMapping("/{queryId}") @Transactional(readOnly = true) @Observed(name = "dbr_queries_find") - @Operation(summary = "Find some query", security = @SecurityRequirement(name = "bearerAuth")) + @Operation(summary = "Find some query", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")}) @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "List queries", @@ -212,7 +212,7 @@ public class StoreEndpoint { @Transactional(readOnly = true) @PreAuthorize("hasAuthority('persist-query')") @Observed(name = "dbr_query_persist") - @Operation(summary = "Persist some query", security = @SecurityRequirement(name = "bearerAuth")) + @Operation(summary = "Persist some query", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")}) @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Persist query successful", diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/TableColumnEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/TableColumnEndpoint.java index 999a66bb70f150e7fa1459724f782eca4744636c..47193508ba32c0cd0ee33091b5860f7c3380b5c7 100644 --- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/TableColumnEndpoint.java +++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/TableColumnEndpoint.java @@ -49,7 +49,7 @@ public class TableColumnEndpoint { @Transactional @PreAuthorize("hasAuthority('modify-table-column-semantics') or hasAuthority('modify-foreign-table-column-semantics')") @Observed(name = "dbr_semantics_column_save") - @Operation(summary = "Update a table column semantic mapping", security = @SecurityRequirement(name = "bearerAuth")) + @Operation(summary = "Update a table column semantic mapping", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")}) @ApiResponses(value = { @ApiResponse(responseCode = "202", description = "Updated column semantics successfully", diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/TableDataEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/TableDataEndpoint.java index d71a97293cf3bdace25a0c2fd28ea0e34f9196b8..fe12e3aeff6d8e7224e1b57b5f54436fc2ac1f7b 100644 --- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/TableDataEndpoint.java +++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/TableDataEndpoint.java @@ -5,7 +5,6 @@ import at.tuwien.api.database.query.ImportDto; import at.tuwien.api.database.query.QueryResultDto; import at.tuwien.api.database.table.TableCsvDeleteDto; import at.tuwien.api.database.table.TableCsvDto; -import at.tuwien.api.database.table.columns.ColumnDto; import at.tuwien.api.error.ApiErrorDto; import at.tuwien.entities.database.Database; import at.tuwien.exception.*; @@ -15,6 +14,7 @@ import at.tuwien.utils.PrincipalUtil; import at.tuwien.utils.UserUtil; import at.tuwien.validation.EndpointValidator; import io.micrometer.observation.annotation.Observed; +import io.swagger.v3.oas.annotations.ExternalDocumentation; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.Schema; @@ -55,7 +55,8 @@ public class TableDataEndpoint { @Transactional @Observed(name = "dbr_table_data_insert") @PreAuthorize("hasAuthority('insert-table-data')") - @Operation(summary = "Insert data", security = @SecurityRequirement(name = "bearerAuth")) + @Operation(summary = "Insert data", description = "Insert data directly as key-value map tuple", + security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")}) @ApiResponses(value = { @ApiResponse(responseCode = "202", description = "Inserted data successfully"), @@ -94,7 +95,8 @@ public class TableDataEndpoint { @Transactional @PreAuthorize("hasAuthority('delete-table-data')") @Observed(name = "dbr_table_data_delete") - @Operation(summary = "Delete data", security = @SecurityRequirement(name = "bearerAuth")) + @Operation(summary = "Delete data", description = "Delete a tuples that match a key-value map", + security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")}) @ApiResponses(value = { @ApiResponse(responseCode = "202", description = "Deleted table data successfully"), @@ -133,7 +135,7 @@ public class TableDataEndpoint { @Transactional @PreAuthorize("hasAuthority('insert-table-data')") @Observed(name = "dbr_table_data_import") - @Operation(summary = "Insert data from csv", security = @SecurityRequirement(name = "bearerAuth")) + @Operation(summary = "Insert data from csv", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")}) @ApiResponses(value = { @ApiResponse(responseCode = "202", description = "Import table data successfully"), @@ -181,7 +183,7 @@ public class TableDataEndpoint { @RequestMapping(method = {RequestMethod.GET, RequestMethod.HEAD}) @Transactional(readOnly = true) @Observed(name = "dbr_table_data_findall") - @Operation(summary = "Find data", security = @SecurityRequirement(name = "bearerAuth")) + @Operation(summary = "Find data", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")}) @ApiResponses(value = { @ApiResponse(responseCode = "202", description = "Get table data successfully"), @@ -237,7 +239,7 @@ public class TableDataEndpoint { @GetMapping("/count") @Transactional(readOnly = true) @Observed(name = "dbr_table_data_countall") - @Operation(summary = "Find data", security = @SecurityRequirement(name = "bearerAuth")) + @Operation(summary = "Find data", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")}) @ApiResponses(value = { @ApiResponse(responseCode = "202", description = "Get table data count successfully"), 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 e3be34e34746452667def2da8ef63d937d6fdf62..a7f88258b70956bd5417eda11a0751f3bfcfd188 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 @@ -61,7 +61,7 @@ public class TableEndpoint { @GetMapping @Transactional(readOnly = true) @Observed(name = "dbr_tables_findall") - @Operation(summary = "List all tables", security = @SecurityRequirement(name = "bearerAuth")) + @Operation(summary = "List all tables", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")}) @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "List tables", @@ -97,7 +97,7 @@ public class TableEndpoint { @Transactional @PreAuthorize("hasAuthority('create-table')") @Observed(name = "dbr_table_create") - @Operation(summary = "Create a table", security = @SecurityRequirement(name = "bearerAuth")) + @Operation(summary = "Create a table", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")}) @ApiResponses(value = { @ApiResponse(responseCode = "201", description = "Created a new table", @@ -150,7 +150,7 @@ public class TableEndpoint { @GetMapping("/{tableId}") @Transactional(readOnly = true) @Observed(name = "dbr_tables_find") - @Operation(summary = "Get information about table", security = @SecurityRequirement(name = "bearerAuth")) + @Operation(summary = "Get information about table", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")}) @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Find table successfully", @@ -193,7 +193,7 @@ public class TableEndpoint { @Transactional @PreAuthorize("hasAuthority('delete-table') or hasAuthority('delete-foreign-table')") @Observed(name = "dbr_table_delete") - @Operation(summary = "Delete a table", security = @SecurityRequirement(name = "bearerAuth")) + @Operation(summary = "Delete a table", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")}) @ApiResponses(value = { @ApiResponse(responseCode = "202", description = "Delete table successfully", diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/TableHistoryEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/TableHistoryEndpoint.java index 727b3f69c3c27d8e1a652445dcbd753bc9f37ddd..dcf9e9199a3d47c3f30510acfb98e043ce1572dc 100644 --- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/TableHistoryEndpoint.java +++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/TableHistoryEndpoint.java @@ -39,7 +39,7 @@ public class TableHistoryEndpoint { @RequestMapping(method = {RequestMethod.GET, RequestMethod.HEAD}) @Transactional(readOnly = true) @Observed(name = "dbr_table_history_findall") - @Operation(summary = "Find all history", security = @SecurityRequirement(name = "bearerAuth")) + @Operation(summary = "Find all history", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")}) @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Find table history successfully", 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 4b9418005bfd9df475992e37fbff6c1978c371d7..aa63d1110c9ce03a88d4f9143f909342a910eaaa 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 @@ -147,7 +147,7 @@ public class UserEndpoint { @Transactional @PreAuthorize("isAuthenticated() or hasAuthority('find-user')") @Observed(name = "dbr_user_find") - @Operation(summary = "Get a user info", security = @SecurityRequirement(name = "bearerAuth")) + @Operation(summary = "Get a user info", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")}) @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Found user", @@ -189,7 +189,7 @@ public class UserEndpoint { @Transactional @PreAuthorize("hasAuthority('modify-user-information')") @Observed(name = "dbr_user_modify") - @Operation(summary = "Modify user information", security = @SecurityRequirement(name = "bearerAuth")) + @Operation(summary = "Modify user information", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")}) @ApiResponses(value = { @ApiResponse(responseCode = "202", description = "Modified user information", @@ -240,7 +240,7 @@ public class UserEndpoint { @Transactional @PreAuthorize("hasAuthority('modify-user-theme')") @Observed(name = "dbr_user_theme_modify") - @Operation(summary = "Modify user theme", security = @SecurityRequirement(name = "bearerAuth")) + @Operation(summary = "Modify user theme", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")}) @ApiResponses(value = { @ApiResponse(responseCode = "202", description = "Modified user theme", @@ -285,7 +285,7 @@ public class UserEndpoint { @Transactional @PreAuthorize("isAuthenticated()") @Observed(name = "dbr_user_password_modify") - @Operation(summary = "Modify user password", security = @SecurityRequirement(name = "bearerAuth")) + @Operation(summary = "Modify user password", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")}) @ApiResponses(value = { @ApiResponse(responseCode = "202", description = "Modified user password", diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ViewEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ViewEndpoint.java index fd379d6afd4468a6cd0fda52b8f349425335c3a6..f3a1b76c06de61b3867fac1c1415f5034d179b21 100644 --- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ViewEndpoint.java +++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ViewEndpoint.java @@ -62,7 +62,7 @@ public class ViewEndpoint { @GetMapping @Transactional(readOnly = true) @Observed(name = "dbr_views_findall") - @Operation(summary = "Find all views", security = @SecurityRequirement(name = "bearerAuth")) + @Operation(summary = "Find all views", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")}) @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Find views successfully", @@ -93,7 +93,7 @@ public class ViewEndpoint { @Transactional @PreAuthorize("hasAuthority('create-database-view')") @Observed(name = "dbr_view_create") - @Operation(summary = "Create a view", security = @SecurityRequirement(name = "bearerAuth")) + @Operation(summary = "Create a view", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")}) @ApiResponses(value = { @ApiResponse(responseCode = "201", description = "Create view successfully", @@ -160,7 +160,7 @@ public class ViewEndpoint { @GetMapping("/{viewId}") @Transactional(readOnly = true) @Observed(name = "dbr_view_find") - @Operation(summary = "Find one view", security = @SecurityRequirement(name = "bearerAuth")) + @Operation(summary = "Find one view", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")}) @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Find view successfully", @@ -194,7 +194,7 @@ public class ViewEndpoint { @Transactional @PreAuthorize("hasAuthority('delete-database-view')") @Observed(name = "dbr_view_delete") - @Operation(summary = "Delete one view", security = @SecurityRequirement(name = "bearerAuth")) + @Operation(summary = "Delete one view", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")}) @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Delete view successfully", @@ -250,7 +250,7 @@ public class ViewEndpoint { @GetMapping("/{viewId}/data") @Transactional(readOnly = true) @Observed(name = "dbr_view_data_findall") - @Operation(summary = "Find view data", security = @SecurityRequirement(name = "bearerAuth")) + @Operation(summary = "Find view data", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")}) @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Find data successfully", @@ -307,7 +307,7 @@ public class ViewEndpoint { @GetMapping("/{viewId}/data/count") @Transactional(readOnly = true) @Observed(name = "dbr_view_data_count") - @Operation(summary = "Find view data count", security = @SecurityRequirement(name = "bearerAuth")) + @Operation(summary = "Find view data count", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")}) @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Count data successfully", 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 5db5076f6a90d66395f3803e235b11c2aa10bb8c..ed462f3bc4aaffba60597363253f601fc22ff7d0 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 @@ -40,7 +40,7 @@ spring: loadbalancer.ribbon.enabled: false management.endpoints.web.exposure.include: health,info,prometheus server: - port: 9099 + port: 19099 logging: pattern.console: "%d %highlight(%-5level) %msg%n" level: @@ -66,6 +66,7 @@ fda: endpoint: "http://authentication-service:8080" username: fda password: fda + clientSecret: MUwRc7yfXSJwX8AdRMWaQC3Nep1VjwgG 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,-- website: http://localhost minConcurrent: 1 diff --git a/dbrepo-metadata-service/rest-service/src/main/resources/application.yml b/dbrepo-metadata-service/rest-service/src/main/resources/application.yml index 341ba025441566c796dd29d1bd945ffc1b344774..26bcbeb8431f79a6ebbb09e6f15b464c8ea510d8 100644 --- a/dbrepo-metadata-service/rest-service/src/main/resources/application.yml +++ b/dbrepo-metadata-service/rest-service/src/main/resources/application.yml @@ -79,6 +79,7 @@ fda: endpoint: "${KEYCLOAK_HOST}" username: "${KEYCLOAK_ADMIN}" password: "${KEYCLOAK_ADMIN_PASSWORD}" + clientSecret: "${KEYCLOAK_CLIENT_SECRET}" unsupported: "${NOT_SUPPORTED_KEYWORDS}" website: "${WEBSITE}" minConcurrent: "${MIN_CONCURRENT_CONSUMERS}" diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/auth/AuthTokenFilter.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/auth/AuthTokenFilter.java index 647f23867be68d0f5f953934d460185c3fff0afd..dca11b65a1e4fb5ea0fd9c1ea163ce15da76db25 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/auth/AuthTokenFilter.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/auth/AuthTokenFilter.java @@ -6,6 +6,7 @@ import com.auth0.jwt.JWT; import com.auth0.jwt.JWTVerifier; import com.auth0.jwt.algorithms.Algorithm; import com.auth0.jwt.interfaces.DecodedJWT; +import com.auth0.jwt.interfaces.Verification; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; @@ -56,6 +57,10 @@ public class AuthTokenFilter extends OncePerRequestFilter { } public UserDetails verifyJwt(String token) throws ServletException { + return verifyJwt(token, true); + } + + public UserDetails verifyJwt(String token, boolean strict) throws ServletException { final KeyFactory kf; try { kf = KeyFactory.getInstance("RSA"); @@ -72,10 +77,12 @@ public class AuthTokenFilter extends OncePerRequestFilter { throw new ServletException("Provided public key is invalid", e); } final Algorithm algorithm = Algorithm.RSA256(pubKey, null); - JWTVerifier verifier = JWT.require(algorithm) - .withIssuer(issuer) - .withAudience("spring") - .build(); + Verification verification = JWT.require(algorithm) + .withAudience("spring"); + if (strict) { + verification = verification.withIssuer(issuer); + } + final JWTVerifier verifier = verification.build(); final DecodedJWT jwt = verifier.verify(token); final RealmAccessDto realmAccess = jwt.getClaim("realm_access").as(RealmAccessDto.class); return UserDetailsDto.builder() diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/auth/BasicAuthenticationProvider.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/auth/BasicAuthenticationProvider.java new file mode 100644 index 0000000000000000000000000000000000000000..f4bfbcc820834d9ffce41cd8d37d3c6a0306d020 --- /dev/null +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/auth/BasicAuthenticationProvider.java @@ -0,0 +1,42 @@ +package at.tuwien.auth; + +import at.tuwien.api.keycloak.TokenDto; +import at.tuwien.exception.AccessDeniedException; +import at.tuwien.exception.KeycloakRemoteException; +import at.tuwien.gateway.KeycloakGateway; +import jakarta.servlet.ServletException; +import lombok.extern.log4j.Log4j2; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.stereotype.Component; + +@Log4j2 +@Component +public class BasicAuthenticationProvider implements AuthenticationManager { + + private final AuthTokenFilter authTokenFilter; + private final KeycloakGateway keycloakGateway; + + @Autowired + public BasicAuthenticationProvider(AuthTokenFilter authTokenFilter, KeycloakGateway keycloakGateway) { + this.authTokenFilter = authTokenFilter; + this.keycloakGateway = keycloakGateway; + } + + @Override + public Authentication authenticate(Authentication auth) throws AuthenticationException { + try { + final TokenDto tokenDto = keycloakGateway.obtainUserToken(auth.getName(), auth.getCredentials().toString()); + final UserDetails userDetails = authTokenFilter.verifyJwt(tokenDto.getAccessToken(), false); + log.debug("authenticated user {}", userDetails); + return new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); + } catch (AccessDeniedException | KeycloakRemoteException | ServletException e) { + throw new BadCredentialsException("Failed to authenticate with authentication service", e); + } + } +} diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/KeycloakConfig.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/KeycloakConfig.java index 241ea9c4b538c3670f58a5807067cb2db4d35113..d47b1080ef1d0c2d69a0c163f289b27a37613503 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/KeycloakConfig.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/KeycloakConfig.java @@ -21,6 +21,9 @@ public class KeycloakConfig { @Value("${fda.keycloak.password}") private String keycloakPassword; + @Value("${fda.keycloak.clientSecret}") + private String keycloakClientSecret; + @Bean("keycloakRestTemplate") public RestTemplate brokerRestTemplate() { final RestTemplate restTemplate = new RestTemplate(); diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/WebSecurityConfig.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/WebSecurityConfig.java index 55bbb9f8b869c2178d2c3ac25a1cf2947fbd0cf9..8fc09851fd44238a2f30e43c77478f1aa51ed3f2 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/WebSecurityConfig.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/WebSecurityConfig.java @@ -1,6 +1,8 @@ package at.tuwien.config; import at.tuwien.auth.AuthTokenFilter; +import at.tuwien.auth.BasicAuthenticationProvider; +import at.tuwien.gateway.KeycloakGateway; import io.swagger.v3.oas.annotations.enums.SecuritySchemeType; import io.swagger.v3.oas.annotations.security.SecurityScheme; import jakarta.servlet.http.HttpServletResponse; @@ -12,6 +14,7 @@ import org.springframework.security.config.annotation.web.configuration.EnableWe import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import org.springframework.security.web.util.matcher.OrRequestMatcher; import org.springframework.web.cors.CorsConfiguration; @@ -27,6 +30,11 @@ import org.springframework.web.filter.CorsFilter; bearerFormat = "JWT", scheme = "bearer" ) +@SecurityScheme( + name = "basicAuth", + type = SecuritySchemeType.HTTP, + scheme = "basic" +) public class WebSecurityConfig { @Bean @@ -35,7 +43,7 @@ public class WebSecurityConfig { } @Bean - public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + public SecurityFilterChain filterChain(HttpSecurity http, KeycloakGateway keycloakGateway) throws Exception { final OrRequestMatcher internalEndpoints = new OrRequestMatcher( new AntPathRequestMatcher("/actuator/**", "GET"), new AntPathRequestMatcher("/v3/api-docs.yaml"), @@ -77,6 +85,9 @@ public class WebSecurityConfig { http.addFilterBefore(authTokenFilter(), UsernamePasswordAuthenticationFilter.class ); + http.addFilterBefore(new BasicAuthenticationFilter(new BasicAuthenticationProvider(authTokenFilter(), keycloakGateway)), + UsernamePasswordAuthenticationFilter.class + ); return http.build(); } diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/KeycloakGateway.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/KeycloakGateway.java index 3614e43fcbbbc21c8f9808974355b97b0d6750a4..0a9dcf6b69434afe1b8c0bf4b36ab6566c78e20a 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/KeycloakGateway.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/KeycloakGateway.java @@ -1,5 +1,6 @@ package at.tuwien.gateway; +import at.tuwien.api.keycloak.TokenDto; import at.tuwien.api.keycloak.UserCreateDto; import at.tuwien.api.keycloak.UserDto; import at.tuwien.api.user.UserPasswordDto; @@ -9,6 +10,8 @@ import java.util.UUID; public interface KeycloakGateway { + TokenDto obtainUserToken(String username, String password) throws AccessDeniedException, KeycloakRemoteException; + /** * Creates a user at the Authentication Service with given credentials. * diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/KeycloakGatewayImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/KeycloakGatewayImpl.java index fbf2c7b2518bf23d1b3f96b33628459b87b0dd94..62351acf6430b23bef48e6a96c27bd0d2377c5d0 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/KeycloakGatewayImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/KeycloakGatewayImpl.java @@ -48,10 +48,37 @@ public class KeycloakGatewayImpl implements KeycloakGateway { response = restTemplate.exchange(url, HttpMethod.POST, new HttpEntity<>(payload, headers), TokenDto.class); } catch (ResourceAccessException | HttpServerErrorException.ServiceUnavailable e) { log.error("Failed to obtain admin token: {}", e.getMessage()); - throw new AccessDeniedException("Failed to obtain admin token: " + e.getMessage()); + throw new AccessDeniedException("Failed to obtain admin token: " + e.getMessage(), e); } catch (Exception e) { - log.error("Failed to create user: remote host answered unexpected: {}", e.getMessage()); - throw new KeycloakRemoteException("Failed to create user: remote host answered unexpected: " + e.getMessage(), e); + log.error("Failed to obtain admin token: remote host answered unexpected: {}", e.getMessage(), e); + throw new KeycloakRemoteException("Failed to obtain admin token: remote host answered unexpected: " + e.getMessage(), e); + } + return response.getBody(); + } + + @Override + public TokenDto obtainUserToken(String username, String password) throws AccessDeniedException, KeycloakRemoteException { + final HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); + final MultiValueMap<String, String> payload = new LinkedMultiValueMap<>(); + payload.add("username", username); + payload.add("password", password); + payload.add("grant_type", "password"); + payload.add("scope", "openid roles attributes"); + payload.add("client_id", "dbrepo-client"); + payload.add("client_secret", keycloakConfig.getKeycloakClientSecret()); + final String url = keycloakConfig.getKeycloakEndpoint() + "/realms/dbrepo/protocol/openid-connect/token"; + log.debug("request user token from url {}", url); + final ResponseEntity<TokenDto> response; + try { + response = new RestTemplate() + .exchange(url, HttpMethod.POST, new HttpEntity<>(payload, headers), TokenDto.class); + } catch (ResourceAccessException | HttpServerErrorException.ServiceUnavailable e) { + log.error("Failed to obtain user token: {}", e.getMessage()); + throw new AccessDeniedException("Failed to obtain user token: " + e.getMessage(), e); + } catch (Exception e) { + log.error("Failed to obtain user token: remote host answered unexpected: {}", e.getMessage(), e); + throw new KeycloakRemoteException("Failed to obtain user token: remote host answered unexpected: " + e.getMessage(), e); } return response.getBody(); } diff --git a/dbrepo-search-service/app/__init__.py b/dbrepo-search-service/app/__init__.py index e090b89e1d966bfb61c0c511efd3a978d0fc8cff..f14faf60b41ce59a50d43365d9f0c2c03d362496 100644 --- a/dbrepo-search-service/app/__init__.py +++ b/dbrepo-search-service/app/__init__.py @@ -66,7 +66,7 @@ def create_app(config_class=Config): "info": { "title": "Database Repository Search Service API", "description": "Service that searches the search database", - "version": "latest", + "version": "__APPVERSION__", "contact": { "name": "Prof. Andreas Rauber", "email": "andreas.rauber@tuwien.ac.at" diff --git a/docker-compose.yml b/docker-compose.yml index d783a4b77f19e284f156ec33d33f23ff985555f2..9eeafdeeb6c2c917229e93b033297e01114b7a73 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -150,6 +150,7 @@ services: KEYCLOAK_HOST: "${KEYCLOAK_HOST:-http://authentication-service:8080}" KEYCLOAK_ADMIN: "${KEYCLOAK_ADMIN:-fda}" KEYCLOAK_ADMIN_PASSWORD: "${KEYCLOAK_ADMIN_PASSWORD:-fda}" + KEYCLOAK_CLIENT_SECRET: "${KEYCLOAK_CLIENT_SECRET:-MUwRc7yfXSJwX8AdRMWaQC3Nep1VjwgG}" DATACITE_URL: "${DATACITE_URL:-https://api.test.datacite.org}" DATACITE_PREFIX: "${DATACITE_PREFIX:-}" DATACITE_USERNAME: "${DATACITE_USERNAME:-}" diff --git a/mkdocs.yml b/mkdocs.yml index ae8084fafc40d7832f7bf97b9965008a4ea55fd6..14affa17a9a3a1ebb0687936f79c7895f73c3b19 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -22,7 +22,7 @@ nav: - Storage Service: system-services-storage.md - Upload Service: system-services-upload.md - Databases: - - Auth Database: system-databases-auth.md + - Authentication Database: system-databases-authentication.md - Data Database: system-databases-data.md - Metadata Database: system-databases-metadata.md - Search Database: system-databases-search.md @@ -33,8 +33,10 @@ nav: - Overview: usage-overview.md - Services: - Analyse Service: usage-analyse.md - - Authentication Service: usage-auth.md + - Authentication Service: usage-authentication.md - Broker Service: usage-broker.md + - Metadata Service: usage-metadata.md + - Search Service: usage-search.md - Storage Service: usage-storage.md - Upload Service: usage-upload.md - publications.md diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index c7dd197a44b15e5c7cca6376a7cc0287a7d60c74..0000000000000000000000000000000000000000 --- a/requirements.txt +++ /dev/null @@ -1,8 +0,0 @@ -mkdocs==1.4.3 -mkdocs-material==9.1.17 -mkdocs-with-pdf==0.9.3 -mkdocs-material-extensions>=1.0.3 -requests>=2.27.0 -py-dotenv>=0.1 -python-dotenv==1.0.0 -requests==2.31.0 \ No newline at end of file