diff --git a/.fda-deployment/fda-container-service/create-container-traffic.json b/.fda-deployment/fda-container-service/create-container-traffic.json deleted file mode 100644 index b602860c176e5490e5e7a9ffbee79ace1f9f09f3..0000000000000000000000000000000000000000 --- a/.fda-deployment/fda-container-service/create-container-traffic.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "name": "Public Transport in Zurich", - "repository": "mariadb", - "tag": "10.5" -} \ No newline at end of file diff --git a/.fda-deployment/fda-container-service/start-container-traffic.json b/.fda-deployment/fda-container-service/start-container-traffic.json deleted file mode 100644 index b7342e513ffe44aa7f94a9fb81015e901a49796f..0000000000000000000000000000000000000000 --- a/.fda-deployment/fda-container-service/start-container-traffic.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "action": "START" -} \ No newline at end of file diff --git a/.fda-deployment/fda-database-service/create-database-traffic.json b/.fda-deployment/fda-database-service/create-database-traffic.json deleted file mode 100644 index d399aaf55fc4ff20caabad7974116ee83b77c6a9..0000000000000000000000000000000000000000 --- a/.fda-deployment/fda-database-service/create-database-traffic.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "description": "Public transport routes and schedules for the city of Zurich", - "is_public": true, - "name": "Public Transport in Zurich" -} \ No newline at end of file diff --git a/.fda-deployment/fda-query-service/create-query-air1.json b/.fda-deployment/fda-query-service/create-query-air1.json deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/.fda-deployment/fda-query-service/create-query-air2.json b/.fda-deployment/fda-query-service/create-query-air2.json deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/.fda-deployment/fda-query-service/create-query-air3.json b/.fda-deployment/fda-query-service/create-query-air3.json deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/.fda-deployment/fda-query-service/create-query-infection1.json b/.fda-deployment/fda-query-service/create-query-infection1.json deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/.fda-deployment/fda-query-service/create-query-infection2.json b/.fda-deployment/fda-query-service/create-query-infection2.json deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/.fda-deployment/fda-query-service/create-query-infection3.json b/.fda-deployment/fda-query-service/create-query-infection3.json deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/.fda-deployment/fda-query-service/create-query-weather1.json b/.fda-deployment/fda-query-service/create-query-weather1.json deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/.fda-deployment/fda-query-service/create-query-weather2.json b/.fda-deployment/fda-query-service/create-query-weather2.json deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/.fda-deployment/fda-query-service/create-query-weather3.json b/.fda-deployment/fda-query-service/create-query-weather3.json deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/.fda-deployment/fda-table-service/create-table-traffic.json b/.fda-deployment/fda-table-service/create-table-traffic.json deleted file mode 100644 index e2c7ed73f431dbb13b526f773390a4f9cd24f3d0..0000000000000000000000000000000000000000 --- a/.fda-deployment/fda-table-service/create-table-traffic.json +++ /dev/null @@ -1,414 +0,0 @@ -{ - "columns": [ - { - "check_expression": null, - "date_format": null, - "enum_values": [], - "foreign_key": null, - "name": "linie", - "null_allowed": false, - "primary_key": false, - "references": null, - "type": "NUMBER", - "unique": false - }, - { - "check_expression": null, - "date_format": null, - "enum_values": [], - "foreign_key": null, - "name": "richtung", - "null_allowed": false, - "primary_key": false, - "references": null, - "type": "NUMBER", - "unique": false - }, - { - "check_expression": null, - "date_format": "dd.MM.yy", - "enum_values": [], - "foreign_key": null, - "name": "betriebsdatum", - "null_allowed": false, - "primary_key": false, - "references": null, - "type": "DATE", - "unique": false - }, - { - "check_expression": null, - "date_format": null, - "enum_values": [], - "foreign_key": null, - "name": "fahrzeug", - "null_allowed": false, - "primary_key": false, - "references": null, - "type": "NUMBER", - "unique": false - }, - { - "check_expression": null, - "date_format": null, - "enum_values": [], - "foreign_key": null, - "name": "kurs", - "null_allowed": false, - "primary_key": false, - "references": null, - "type": "NUMBER", - "unique": false - }, - { - "check_expression": null, - "date_format": null, - "enum_values": [], - "foreign_key": null, - "name": "seq_von", - "null_allowed": false, - "primary_key": false, - "references": null, - "type": "NUMBER", - "unique": false - }, - { - "check_expression": null, - "date_format": null, - "enum_values": [], - "foreign_key": null, - "name": "halt_diva_von", - "null_allowed": false, - "primary_key": false, - "references": null, - "type": "NUMBER", - "unique": false - }, - { - "check_expression": null, - "date_format": null, - "enum_values": [], - "foreign_key": null, - "name": "halt_punkt_diva_von", - "null_allowed": false, - "primary_key": false, - "references": null, - "type": "NUMBER", - "unique": false - }, - { - "check_expression": null, - "date_format": null, - "enum_values": [], - "foreign_key": null, - "name": "halt_kurz_von1", - "null_allowed": false, - "primary_key": false, - "references": null, - "type": "NUMBER", - "unique": false - }, - { - "check_expression": null, - "date_format": "dd.MM.yy", - "enum_values": [], - "foreign_key": null, - "name": "datum_von", - "null_allowed": false, - "primary_key": false, - "references": null, - "type": "DATE", - "unique": false - }, - { - "check_expression": null, - "date_format": null, - "enum_values": [], - "foreign_key": null, - "name": "soll_an_von", - "null_allowed": false, - "primary_key": false, - "references": null, - "type": "NUMBER", - "unique": false - }, - { - "check_expression": null, - "date_format": null, - "enum_values": [], - "foreign_key": null, - "name": "ist_an_von", - "null_allowed": false, - "primary_key": false, - "references": null, - "type": "NUMBER", - "unique": false - }, - { - "check_expression": null, - "date_format": null, - "enum_values": [], - "foreign_key": null, - "name": "soll_ab_von", - "null_allowed": false, - "primary_key": false, - "references": null, - "type": "NUMBER", - "unique": false - }, - { - "check_expression": null, - "date_format": null, - "enum_values": [], - "foreign_key": null, - "name": "ist_ab_von", - "null_allowed": false, - "primary_key": false, - "references": null, - "type": "NUMBER", - "unique": false - }, - { - "check_expression": null, - "date_format": null, - "enum_values": [], - "foreign_key": null, - "name": "seq_nach", - "null_allowed": false, - "primary_key": false, - "references": null, - "type": "NUMBER", - "unique": false - }, - { - "check_expression": null, - "date_format": null, - "enum_values": [], - "foreign_key": null, - "name": "halt_diva_nach", - "null_allowed": false, - "primary_key": false, - "references": null, - "type": "NUMBER", - "unique": false - }, - { - "check_expression": null, - "date_format": null, - "enum_values": [], - "foreign_key": null, - "name": "halt_punkt_diva_nach", - "null_allowed": false, - "primary_key": false, - "references": null, - "type": "NUMBER", - "unique": false - }, - { - "check_expression": null, - "date_format": null, - "enum_values": [], - "foreign_key": null, - "name": "halt_kurz_nach1", - "null_allowed": false, - "primary_key": false, - "references": null, - "type": "NUMBER", - "unique": false - }, - { - "check_expression": null, - "date_format": "dd.MM.yy", - "enum_values": [], - "foreign_key": null, - "name": "datum_nach", - "null_allowed": false, - "primary_key": false, - "references": null, - "type": "DATE", - "unique": false - }, - { - "check_expression": null, - "date_format": null, - "enum_values": [], - "foreign_key": null, - "name": "soll_an_nach", - "null_allowed": false, - "primary_key": false, - "references": null, - "type": "NUMBER", - "unique": false - }, - { - "check_expression": null, - "date_format": null, - "enum_values": [], - "foreign_key": null, - "name": "ist_an_nach1", - "null_allowed": false, - "primary_key": false, - "references": null, - "type": "NUMBER", - "unique": false - }, - { - "check_expression": null, - "date_format": null, - "enum_values": [], - "foreign_key": null, - "name": "soll_ab_nach", - "null_allowed": false, - "primary_key": false, - "references": null, - "type": "NUMBER", - "unique": false - }, - { - "check_expression": null, - "date_format": null, - "enum_values": [], - "foreign_key": null, - "name": "ist_ab_nach", - "null_allowed": false, - "primary_key": false, - "references": null, - "type": "NUMBER", - "unique": false - }, - { - "check_expression": null, - "date_format": null, - "enum_values": [], - "foreign_key": null, - "name": "fahrt_id", - "null_allowed": false, - "primary_key": false, - "references": null, - "type": "NUMBER", - "unique": false - }, - { - "check_expression": null, - "date_format": null, - "enum_values": [], - "foreign_key": null, - "name": "fahrweg_id", - "null_allowed": false, - "primary_key": false, - "references": null, - "type": "NUMBER", - "unique": false - }, - { - "check_expression": null, - "date_format": null, - "enum_values": [], - "foreign_key": null, - "name": "fw_no", - "null_allowed": false, - "primary_key": false, - "references": null, - "type": "NUMBER", - "unique": false - }, - { - "check_expression": null, - "date_format": null, - "enum_values": [], - "foreign_key": null, - "name": "fw_typ", - "null_allowed": false, - "primary_key": false, - "references": null, - "type": "NUMBER", - "unique": false - }, - { - "check_expression": null, - "date_format": null, - "enum_values": [], - "foreign_key": null, - "name": "fw_kurz", - "null_allowed": false, - "primary_key": false, - "references": null, - "type": "NUMBER", - "unique": false - }, - { - "check_expression": null, - "date_format": null, - "enum_values": [], - "foreign_key": null, - "name": "fw_lang", - "null_allowed": false, - "primary_key": false, - "references": null, - "type": "STRING", - "unique": false - }, - { - "check_expression": null, - "date_format": null, - "enum_values": [], - "foreign_key": null, - "name": "umlauf_von", - "null_allowed": false, - "primary_key": false, - "references": null, - "type": "NUMBER", - "unique": false - }, - { - "check_expression": null, - "date_format": null, - "enum_values": [], - "foreign_key": null, - "name": "halt_id_von", - "null_allowed": false, - "primary_key": false, - "references": null, - "type": "NUMBER", - "unique": false - }, - { - "check_expression": null, - "date_format": null, - "enum_values": [], - "foreign_key": null, - "name": "halt_id_nach", - "null_allowed": false, - "primary_key": false, - "references": null, - "type": "NUMBER", - "unique": false - }, - { - "check_expression": null, - "date_format": null, - "enum_values": [], - "foreign_key": null, - "name": "halt_punkt_id_von", - "null_allowed": false, - "primary_key": false, - "references": null, - "type": "NUMBER", - "unique": false - }, - { - "check_expression": null, - "date_format": null, - "enum_values": [], - "foreign_key": null, - "name": "halt_punkt_id_nach", - "null_allowed": false, - "primary_key": false, - "references": null, - "type": "NUMBER", - "unique": false - } - ], - "description": "Public transport routes and schedules for the city of Zurich https://data.stadt-zuerich.ch/dataset/vbz-fahrzeiten-ogd", - "name": "Public Transport in Zurich" -} diff --git a/.fda-deployment/seed b/.fda-deployment/seed deleted file mode 100755 index c7353553a7d99e6012db59bf5cd026ff24f84984..0000000000000000000000000000000000000000 --- a/.fda-deployment/seed +++ /dev/null @@ -1,61 +0,0 @@ -#!/bin/bash -GATEWAY="$(docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' fda-gateway-service):9095" - -# fda-container-service -STATUS=$(curl -X POST "http://${GATEWAY}/api/container/" \ - -o /dev/null -w "%{http_code}" -s -m 10 -d '@.fda-deployment/fda-container-service/create-container-traffic.json' \ - -H "Content-Type: application/json") -if [ "${STATUS}" != 201 ]; then - echo "[ERROR] container create" - echo "${STATUS}" - exit 1 -fi -echo "[INFO] Created container" -STATUS=$(curl -X PUT "http://${GATEWAY}/api/container/1" \ - -o /dev/null -w "%{http_code}" -s -m 10 -d '@.fda-deployment/fda-container-service/start-container-traffic.json' \ - -H "Content-Type: application/json") -if [ "${STATUS}" != 202 ]; then - echo "[ERROR] container start" - echo "${STATUS}" - exit 2 -fi -echo "[INFO] Started container" -# fda-database-service -STATUS=$(curl -X POST "http://${GATEWAY}/api/container/1/database" \ - -o /dev/null -w "%{http_code}" -s -m 10 -d '@.fda-deployment/fda-database-service/create-database-traffic.json' \ - -H "Content-Type: application/json") -if [ "${STATUS}" != 201 ]; then - echo "[ERROR] database create" - echo "${STATUS}" - exit 3 -fi -echo "[INFO] Created database" -# fda-table-service -STATUS=$(curl -X POST "http://${GATEWAY}/api/container/1/database/1/table" \ - -o /dev/null -w "%{http_code}" -s -m 10 -d '@.fda-deployment/fda-table-service/create-table-traffic.json' \ - -H "Content-Type: application/json") -if [ "${STATUS}" != 201 ]; then - echo "[ERROR] table create" - echo "${STATUS}" - exit 4 -fi -echo "[INFO] Created table" -# fda-query-service -STATUS=$(curl -X POST "http://${GATEWAY}/api/container/1/database/1/table/1/data?location=%2Ftmp%2Ffahrzeitensollist2017011520170121.csv" \ - -o /dev/null -w "%{http_code}" -s -m 10 \ - -H "Content-Type: application/json") -if [ "${STATUS}" != 201 ]; then - echo "[ERROR] dataset import" - echo "${STATUS}" - exit 5 -fi -echo "[INFO] Imported dataset" -#curl -d '@fda-query-service/create-query-air1.json' -X POST "http://${GATEWAY}/api/database/1/query" -H "Content-Type: application/json" -#curl -d '@fda-query-service/create-query-air2.json' -X POST "http://${GATEWAY}/api/database/1/query" -H "Content-Type: application/json" -#curl -d '@fda-query-service/create-query-air3.json' -X POST "http://${GATEWAY}/api/database/1/query" -H "Content-Type: application/json" -#curl -d '@fda-query-service/create-query-infection1.json' -X POST "http://${GATEWAY}/api/database/2/query" -H "Content-Type: application/json" -#curl -d '@fda-query-service/create-query-infection2.json' -X POST "http://${GATEWAY}/api/database/2/query" -H "Content-Type: application/json" -#curl -d '@fda-query-service/create-query-infection3.json' -X POST "http://${GATEWAY}/api/database/2/query" -H "Content-Type: application/json" -#curl -d '@fda-query-service/create-query-weather1.json' -X POST "http://${GATEWAY}/api/database/3/query" -H "Content-Type: application/json" -#curl -d '@fda-query-service/create-query-weather2.json' -X POST "http://${GATEWAY}/api/database/3/query" -H "Content-Type: application/json" -#curl -d '@fda-query-service/create-query-weather3.json' -X POST "http://${GATEWAY}/api/database/3/query" -H "Content-Type: application/json" \ No newline at end of file diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index 31a822f9562641c0072d17816d6368b10a9fb679..df1d27a0704c0e7c2ff793f4bb177db69e3afdd5 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -86,7 +86,7 @@ services: fda-public: ipv4_address: 172.29.0.9 environment: - SPRING_PROFILES_ACTIVE: docker + SPRING_PROFILES_ACTIVE: docker,seeder TZ: Europe/Vienna ports: - "9092:9092" diff --git a/docker-compose.sensors.yml b/docker-compose.sensors.yml index 71b58612d001c0009e48da09ba721c792445a774..da9950952f53fb26d5e7815a6b31fcb23bb8e3f9 100644 --- a/docker-compose.sensors.yml +++ b/docker-compose.sensors.yml @@ -12,6 +12,8 @@ services: fda-public: environment: TZ: Europe/Vienna + EXCHANGE: + KEY: volumes: - /sys/class/thermal:/thermal - /sys/class/hwmon:/hwmon diff --git a/fda-container-service/services/src/main/java/at/tuwien/auth/AuthTokenFilter.java b/fda-container-service/services/src/main/java/at/tuwien/auth/AuthTokenFilter.java index 6bcb362bcd7ed5d338c250782c68145597fce5df..a92f31c071ae273930ee5808cf85c68f39fbe97f 100644 --- a/fda-container-service/services/src/main/java/at/tuwien/auth/AuthTokenFilter.java +++ b/fda-container-service/services/src/main/java/at/tuwien/auth/AuthTokenFilter.java @@ -28,7 +28,6 @@ public class AuthTokenFilter extends OncePerRequestFilter { protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String jwt = parseJwt(request); - log.debug("parsed jwt {}", jwt); if (jwt != null) { final UserDetails userDetails = authenticationServiceGateway.validate(jwt); final UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken( diff --git a/fda-container-service/services/src/main/java/at/tuwien/config/ReadyConfig.java b/fda-container-service/services/src/main/java/at/tuwien/config/ReadyConfig.java index 2f348a31ec1d3d2ec44eeaf101a34766790b894d..d9dda2af81deba78cb503dfa018b4d4fe7c0128c 100644 --- a/fda-container-service/services/src/main/java/at/tuwien/config/ReadyConfig.java +++ b/fda-container-service/services/src/main/java/at/tuwien/config/ReadyConfig.java @@ -1,6 +1,6 @@ package at.tuwien.config; -import at.tuwien.seeder.Seeder; +import at.tuwien.seeder.impl.SeederImpl; import com.google.common.io.Files; import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Autowired; @@ -16,19 +16,11 @@ import java.io.IOException; @Configuration public class ReadyConfig { - private final Seeder seeder; - @Value("${fda.ready.path}") private String readyPath; - @Autowired - public ReadyConfig(Seeder seeder) { - this.seeder = seeder; - } - @EventListener(ApplicationReadyEvent.class) public void init() throws IOException { - seeder.seed(); Files.touch(new File(readyPath)); } diff --git a/fda-container-service/services/src/main/java/at/tuwien/seeder/Seeder.java b/fda-container-service/services/src/main/java/at/tuwien/seeder/Seeder.java index c25844b02d8ae119918a9b8119719492460c7df0..241057caf951d628e2f8935bd4badb27a6a36182 100644 --- a/fda-container-service/services/src/main/java/at/tuwien/seeder/Seeder.java +++ b/fda-container-service/services/src/main/java/at/tuwien/seeder/Seeder.java @@ -1,170 +1,10 @@ package at.tuwien.seeder; -import at.tuwien.entities.container.image.ContainerImage; -import at.tuwien.entities.container.image.ContainerImageDate; -import at.tuwien.entities.container.image.ContainerImageEnvironmentItem; -import at.tuwien.entities.container.image.ContainerImageEnvironmentItemType; -import at.tuwien.repository.jpa.ImageDateRepository; -import at.tuwien.repository.jpa.ImageRepository; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.context.event.EventListener; -import java.util.List; - - -@Slf4j -@Service -public class Seeder { - - private final ImageRepository imageRepository; - private final ImageDateRepository imageDateRepository; - - private final static Long IMAGE_1_ID = 1L; - private final static String IMAGE_1_REPOSITORY = "mariadb"; - private final static String IMAGE_1_TAG = "10.5"; - private final static String IMAGE_1_DIALECT = "org.hibernate.dialect.MariaDBDialect"; - private final static String IMAGE_1_DRIVER = "org.mariadb.jdbc.Driver"; - private final static String IMAGE_1_JDBC = "mariadb"; - private final static String IMAGE_1_LOGO = "iVBORw0KGgoAAAANSUhEUgAAAgAAAAFUCAYAAABSj4SGAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAB3RJTUUH5QEeCBMMYbF1jAAAAAZiS0dEAAAAAAAA+UO7fwAAW6ZJREFUeNrtnQWYXEXW92/cE0JCCEEyEJK0xN2dOHHXnr7a906cEHd3F2QhEFxDsJDgLLv7Lmvfvuv27gK7LKzAGrBYfedU95AQZvretpnunv/vef7PRGe6+1bVqVN1RFEAAAAAkBsE9SpKQG2oBNXrFb82VQlotyhB7Qzpuxfpefq79aRepKZKQagyPjwAAAAg1whorGvJsE8g3UYbgLfo6+ck4aKPSc/QpmEMbR7q4IMEAAAAcoGCUFXFp/rIgFtkyJ8gvefB6Jekd0hLlWC4KT5UAAAAIHs9/tpk9IfR171kuF8nvZ+k4b9Qf4tuAnASAAAAAGSb4W9Lhn+1ElS/R8b6T6SP0mD4L9Sv6Gf0wQcNAAAAlAc+vRoZ4sbyXt+vDiGDv5v0YzLQn6bZ4Jcg9S5SIzwEAAAAIOMGP1SDjO7VZIA7k/ho36Gv99DXX2be4H9NHEfQCQ8FAAAASL/Br0/GvQ1pFBn+ItJ2MroPk76XQiBf+hTQ5uEhAQAAAMlSQJ69T29FBn4IGVWNtIUM7AnSU6Rvk35D+qfHlL0ylHo3Hh4AAAAQ35uvHUvF46N7kwzoOnl8H9ReJf2M9DvSH0l/J32Yfca+RH0LDxYAAEAFMuY6e+x1yJA3ISN4Zay4jk/xqz0Uvz6Xfr+EdJj+7CzpDfKU/50DxjyJKwD1XQwGAAAA+UdBqIrSWm9Ihv36WODdUNLEmIHfQL9+hPSyTIuLeu2iwgkAAADIA4NfnQx7SxIbeoM83DX06+Okp2OBd38umxQ7bAAAAACAzBHUK5MRa02GfhxpAxn6B+j3r5F+GbuL/wRGHhsAAAAA+eHlVyNj34m0Tgmqr8aC79iz/0+OBN59TZVIPUYZQtcscU0fHRsAAAAAFRxfqLLiD9cjz/4aMvg30NejMYOf0143G/yaHTRxeQ9djJhkikNrbfHNW4vE6f2OGE6/r9SmzF7LpxhkAAAAsocWhdXJu/eRwZ9Ehn87ff1+Ptzd1+moieZ9ddFrtCFU1RK3b7LFS8eKpPEv1vIFEXFJF72ssgB+g8EGAAAgGzz+WmTsO5NhWkUG6nnSB7lq7GvFPPy2QwzRb4whpsyyxJKiiNi/xhZPH3C+YvRZxRuB+3c6ousIQ1Qum1OA72LQAQAAKE/DX00JhLuTQToci9Yvs5S8up00cS155cVqPdAQA8eZnjVxhinCYUtKU9nIW2LT0ojYvtwWB9fa4q6tjnhktyOeP1r0NaPPOrnNEZNnmmLXiug1wKu3FIl1SyKiQWe9LEoBv4rBBwAAoJyMv9aVPP67ySC9Sfo43UauZntdtBoQNerT51hikRMRG2+KiBNbbGl879vhiId3n9ejexzx1AHvOnOoSDx/JCYy8i8fL9nQl6Q7t0S9/ZrtNfGNzedPBV6g7xMqtMpiA3A7BiAAAICy8vYrkbdfn4w+F+a5j/TfVIxY1baaqNdZE0266zKCvu8YQxi6JfaussXpfY5nY1yWYi//to226DjMkMGAfHLwCm0c+GqANxLF/2b6bEs06KJnLigwoO3FgAQAAJB5rg/XIMPfg7SDDNBbyRquGuQxN+2hiw5DDTF+uimWzY+I4xtsce5IUVYa/Av12q1R48+ef71Ompgy0xTPHnLEvtW2GDvVFPtX21/+Wz5RWLMoIjoPp3/bWZfZA2neAEQwKAEAAGQWv3p1LLjve8kU6GEv+Mpeuhg83hQmefhbl9niwV1O1hv8i8Wpft1HGjIjYBIZ/yf2OfIqokV/jj/Q5ebg4tOCB3Y64mba5PB7b0afAZ96pGkDcAMGJgAAgMwgI/vVUWRwHo8V60k4mr4LecvzIxFxeJ0tHt/rJHTPnk16cn+RGD3FlHf+g8YZ4iHawPCf8a95Q6BpljhzyJGbgMf2fH1zw++dP4OVCyMycJBPBnhTlOQG4B/0XFpjgAIAAMiE198kdtz/ZqJ5/PU769LIHV5ri1PkJV+cL59r4tc/Y7YlNzTdaEPzCBn/F486IlxoSePfc5Qhjf+O5RHRaoAuNt8cKfV7cbzAc4cd+bnwJuKOzbbYcFNEOKYlPzM+SfDg/f+I1ByDFAAAQPoIhusqgfAwMjQ/82rwOe+9XiddtBliiAV2RDy138lpg3+hniPDPjdkSkN/XT9dZhvwhoBjFxp108W19GfnyKBzJgDXDWjUVRcPxbISbt3oiNduSezn3TDB9LIBOElqhMEKAAAgdQq4dK96rRJUV5P+6rUsLle+Yw+Y77mfPZg/hp/1Ihn6NYsjsigQG3o26HyvzwWBWvQ3xFW9dXHLBoc8+iIxY44patMmgasE8nF/1+GGGDTOFC8nePrBmwgPG4BFik+rgUELAAAgRa9fr64E1P6kB8nA/NOL8a/WTpPR8HynXdKdd66LI/45qp8N/RU9dbkRYM+fj+05EJC9/xULInKTcIA2BI3p952GGeLe7Y64aV5EZjvMmmsmFmdwwBFX9na9AnifNBKDFgAAQIrGP1yNPP7ZZFR+7DXCv6CvIRzLksYu3wx/sbgCYHCwLhp21cQ8eq9nD0ej+m+cEr0OYOPOKYB8/M8bId4A8GaINwitBkY3DXdusRP6mdxYiL+Py+f/uhLQ2mHgAgAASA3Zmlf7i9eofs7dv3ubIyve5avxf+GII0ZOMqUXz/n9xfX/V5GB5+I/3B/gdCzOYeWCqLc/fKIhnjnoyGA+3iBwQN8rCWY8cPxEnY6uG4Cjii/cAAMXAABAEl6/XkXxqQXkST7iJcKfU9/4bpo74OWr0f/y3p82NnyPX5sMfd8bDenlcyAf9wa4tKsu2t1gyAh+/rd8AtIkFh9wcpstN0b+QdEiQYkGQvJmgQMAXRoJ0UZNLcQABgAAkDh+le/7+5IhecatlG/lWAGfGXMsWTu/LMvtcqocF9G5Z3tU39hsyyNyFufTn9hqy0j7F9OYYsgBe9xrgI/vm/fR5XE+/zm/Dr7f5w3AkfXRTRBXLhw7LXpKMC9iyddhGZYMBEz07j+6mbBlFoVrB8CA1gGDGAAAQIKef7gqGf4byZB8h/RZPGNTvZ0muo00xPblkS9r3GdSbFD5hIHT69gDnzDdlNkFbHhZvkHRe/VisbHk4/l0xSG8FqvxHxxsiIZddNkVkP+cMxtmzbWkV29o1pf/nvsVXN07+jo4PuDk9ugmgV8bnwQk+vO5bDBvMOI8k4/J+B9RfKGaGMgAAAAS3QDcQIbk565NetpFS92ycX31lswZfT72Zu9+oW2JweNMWUSHiwhV9thAhxsI7VudnmsJvucfQxsKbjGsk6HnTQ+/vi03R9MAh040xZOxY33+ysGAHBOxlf6e/91qMuB8bTC30Eq4rwGnEXLMQJX4ZYLfoQ0Aov8BAAAkavy16aTfemnBu6QoIu++M+nxs2cdJk+/eV9d1O2oeTb6F4oj5vnIPh3e//olEWnQuWb/o7G0Rs4EaHuDIVoN1GXDouKiPntWRaP1h0+MBghyTECv0YYooPdybL0tUwgT+fl3bLFFYLDL8X9AfUXxq7UwkAEAAHgjoNYhLSQj8p5bXr9vEBm6jXbC1esS9XbZaF/WPfWGOHxkzoY71dfEAXxs/P2Dooa+OB6Aa/9f0kUTy+ZZX0b0s/d/A20S+PVzPAL/2b5V0ewAvrZIdOPEQYcRw3J7r58owfAgDGYAAABejX890nwyIG+7Rflz1brbN9sZO/LnTQVXyJs915LH/OnoiHdZ9/h1972IU/d6jTJEA3pNyxec/15H19kynW/kZPPLAMjXYnf/9TtpYvy0qPdfXBuATwQ2JHEawYGGnFng6v0DAAAAHo0/R/svIAPyVtz7/rbR3P77dzoZL6xTXEQnLe1wZUEiXVbhSyUGgYv8SEM/yRRnDp338rna39Wy1K/9lX/fZ7Qh2/py45/iq4wGnaNNgk7tdRKuNrh0XsStRfB7SlAdjQENAADA6wbAloFjLpH+HPD2xD4n4930ps+KttJNl/Fn+QYaMnI/2dfF/5e773Hk/oO7zn8GthHdFNim9ZViPhywyO+h/xjjy+JAO1fYMhVwdshK+PSEv4drS+CAdhupIQY0AAAAL8Zf9WL8Dd2S+faZTvFbu9iWEfLpNP4sLtSTbH2CaOS9Jb3vRU7kK0aeU/uadNdket+F/0dVTdn8iEv+FsdJDJ1gyqsIvhpI9DVMn+3a+e9HsmaDT6uMQQ0AAKB0guEa5C1OJsPxB7cOfgsiVpnk99+/wxENu+ppN/5ccMfSraQLDXHsAN/bD5t4PnCPA//CYUtmJXA9gouvMDgdkE8dirsesgffrKcuTxFePOokFA+xe6Vr3v9fFL9qKQWhqhjYAAAASsev1ogV+fmxW+Q8H22XhefPBnXqLFNmGKR7A8CV+u7YnNx74GBELjLExvvgmvNZD3dsjhYC6jHq6ycLy2lDwMGLocLzmw6OA+DNDWcLJLop6jzcEJVKT33kCo13kud/GQY2AACAOJ6/XpkMRi/St+MZzbqddFFklY3xl3fsm2xxXb/0e/9cMKeQPPWXjyXn/bMx54I/M+aY8ipANgA6WiQ3RpwNwEV9Lrz751Q9Purna5O7t54/6ufGP/x9biryfhLBAYZcZKlm/CuR7ykBFSV/AQAAuG0AND95/6/GK+/LxosN1rkjZWP82YAWkrdco336vX/O10/27v/MIUdmD1zfXxdH15835g/vckSAvi+X8724vPDdWx1ZirjtEP0rG4Phk6KnGyc9lv7lfgE30+aDr2DivL8PlUB4FAY1AACA+BSEase6+n0ez/ibetl5/tKg7nZE79FG2o0/B9wdXpt85D/f7XNAIkftv3TsfDoelxTmzQof8V/c6nh1rE6/pp739J86UCS6DDdkEKHXtr/7VtkyjsDlPTqKD/f+AAAA4hFQG5DBuCNaKa6UIj9k7LhLXVkE/F2o3Ss9GTvP4lLB0mtfl3ylQk535NLDLQcYX3b6k7EKZMB7x0r5XlxXgI379DmWqEI///gFNQHu2+HIeAEu4uMl6I+rDboEQ36oBNVNSjBcDwMbAABA6bChCKpryHC8Hy9Snu+bH9/rlKnxZ+1aYYumtAGo1CZ148+eORfaYQ/61ePJv6b5EevLZj8XV+PjUsB8z19cDOjL6P89jug3xhRX9dLEY3vOf477V9uyGdGAsYZrzMEtG215bRHnPf5bBv0F1OYY2AAAAErHp9VUAtosMhq/ixcox41tHisH419cYpdb3HYcarh1uYsr3kTMCVkpt/3lmAFu2MMpfpzSd+HfcTVAbve7yPl6MB97/RzIOGS8Id9T8Z9vWxaRBYRCISuu8T+yzhYd4n8GH5Huoc1cawxsAAAAcYx/qLISCPclo/GTeIaz9UBD3LujfIz/hQbw7m227C7IrX4TifJn75rv4/evsb9WkCcZccoeG2xO/7v477igEP/drSVUFdxKhp6rAhraV2MDViyIBvMtnx8p9difNw9s/OOU+v2CDP/9pBYY2AAAAOIT0BqQXo8X9Md37xfeV5e3OF2Po+x3khHm6nd8KnBxN0Cuu88tcWfMtuT1AQcRnktT3AIb7qmzLLmx4NK9F59UXNWL4wL0L4MCL04Z5GuMTUsjX4k94GBCThlcuzhSaofBwGDd5fRD/Q2pCQY1AACA+ATDdZWAekc875mr23GVu1eOF2XNBqC8dfsmvoM35Abj9H7na7EKHJw3ccbXi/nwycOsuZZs9sN3/hf+HbfwrdFO+9oGgFP99qyKuAX8fRTz/FHoBwAAgJvx12uRwVgYjRYv2bBwpTou9FPWEf/Zri2xsr/82bx4UYofH+1zYODGElr5ctzAiEmmzA64+HqA4xL4M7/w/3FJ4RULI6JJd9eAP77zvw6DGgAAQHwKQlWUgDaGDMcvo/fGJaT7tdfE2GnlE/Gf7eJAvNnkyV8c/FdczOfSrpo4VUJHxEf3OLIwEJftve+ieIriDUDxVQt/7lydsFE3t1Q/7SQC/gAAAHgjoLanDcBZMh6fltjgp40mg81SjZTPV3EMAFcALKl+gKpaMgugpP/3wE5HXNtPF6Mmm+LJA1/fAHAVQP43fN/PGRd8khDH+PPG7QgC/gAAAHjDrzYk47+LjMfHpRkXjlI/tj75AjkVWXxs//zRkv+OTwy6jzTEYiciAwK/kjoYsUSX4boMDry2X9xI/+KAvz30HC/FgAYAAODB+IerkffvxHLFRWlH/3zvDGOegeyF40Xiqf3O17IDeKPFxYP49IA3Xy5e/5/I+K+QAZwAAACAJwJadzIg75SaL99GE2OmmqV6sFBmNgWcVTB0giE3X3GM/2exmA1DCeq1MZgBAAB4w6c1JePxXLxj5fY3GLLQzmswzGUWS7B0XkTW/3epbsie/xtKQB1Pxh+ePwAAAI8UhKqT8dgU796fS+RuuCkiPVIY58zr0b2OLGLUsIuniobfJnWV2RsAAACAZwLqcDIgv4537z9rLo7+y0rcfrjjMEM2JXI3/irn+PsxiAEAACTi+VdS/GQ8gtoLpRkYTvnjzngXV7SDMuD173FEYWG0EqCL4f88Guyn3awEdbTzBQAAkCA+9VLy/veVlu/P4qY1h9baMNAZFJfz5bTKPjcaXo77+b7/f0hTaQNXDYMYAABAYvjVqmT8J5Mh+XM8g2MaFox0BvXEPke2BeYCQB6M/yekJ+i59cYABgAAkBytw82UoPq9eAaH76FR6jdzrYvv3GLL0sDc5reSu/F/n57XbjL+LTF4AQAAJE9APRSvxS/Xq9+3GtX+MiH+TLcsi4hr+uiyvK8Hz/8tel7zFF+4keILVcLgBQAAkDgFocrRfHHZJa5Eg8PR55ZhIeo/A14/NwGaOcfyYvSLj/zPKMFwFwxcAAAAqeELt1CC6ndK6/JXuY0mg9Ee3IWj/3Tq3JEisX91RHQd4VrUp1gf0EbtpBLUm2HQAgAASNH4a/WVgMYFf/5ZmuHh3vKbb0at/3TqucNFYqFtiYK+utxgeTD+vyOtVVqrjTFoAQAApAZXifOrY8mw/KY0w8Md5ibMMKW3CsOdHp097Mj+CZd29RTlzzEZP6RN2jQS8vsBAACkgYB2FenBeIF/XO6Xi9HAcKdH9+90RI+RptdAvy+UgLya6UEbteoYsAAAAFInqNcgw7IyngGq3l6TveZhuNPTxGfH8oho3kf3Guz3byWonlYKQnUwWAEAAKTT++8Sr80va+A4HP2nQ2cOOWKxExGX9/Bs/N8l47+L1AADFQAAQPrwheoqAfWReEbo6t66OLgWOf+p6vkjjpgTMkXjbp6N/5ukpbRBQ7AfAACAdHv/aiEZmX/Ey/kPq5Y4exgGPBU9ud8R02abonZHzavxf4+8fkcJhuH5AwAASLf3rxWQoXm9tJx/We53qCHu3kreP4x40nrqgCNGTzZFzQ6ejf8Hil8bR8a/NgYpAACA9NKKPMuAepSMzX9LL/eri1WLEPiXSknfh3Y5Ysh402txH96I/VYJ6v0wQAEAAKSfoF6VDM2EqLEp2RixwRo60cTRfwp6cKcjRkwyZf0Ejzn+/0saLZ8PAAAAkP4NgDz6Px3PIHGU+m2bbBjypEv7OmLcNM/Gnz3/H5PGyZRMAAAAIP3GP1xdCarzyNj8K55Rmj3XFK8chyFPRi8eKxKhwoQC/jjVr5CMf00MUAAAAJmhdZi8f/XNeAapeV9dPLYXFf+SFcdNNOzqOdXvU3oeOgL+AAAAZND716srAfWueAaJI9U33BSRrWlhzBPTy8eLxGoy/pd1T6DCX0BbgYEJAAAgswS0G6NlZUs2SNyJbvhEUzyxD95/whH/JI6ZCA42vBr/j8jzP0iqj4EJAAAgc/i162gD8GK8Zj/Neuli5wp4/0kV+jngiFFTPKf7fUZ6XAmo12FgAgAAyBwFoWpkbFbGq/jH0erjp5uyVj0MemLiDdNix/Ia9McbsG/SZqw7PZfKGJwAAAAyR1DtTUbnB/Eq/l3bTxe3I+0vKZ3cZosGnT3f+79Nz2Mscv0BAABkFr92OXmbJ+IG/rXXxPwIKv4l29q35ygjkba+8zAoAQAAZNr4VyXjP5UMz9/iGaY2Qwxx5hCMeTJatzgi6nbymu+vnlQKQrUwMAEAAGR4AxBuHmv2U6pRqt1BEzuWw/tPRqf2OaL7SENmT3jYAHClv7YYlAAAADJPQN0ULTRTumG6YYIhnjuMwL9kxPUSPOb8/50UUgJadQxKAAAAmcWn+cnovBPPMDXtqYuj623ZtQ4GPTE9dyha69+D9/8J6TipCQYlAACADHv+Wj3y/p+Kl/NfrZ0mCsMWuv0lqYNrbXF1b91Lk5/X6Xl0xKAEAACQYc9f5vxbZHjeK80wVSKvtdMwQ9y1FUf/yZb8XeREvHT6e5+exQIMSgAAAJknqHYkvRLP++ecdTZgr+DoPylxqeSB4wwv3v9Zxa9egUEJAAAgs/jV+mR0NkfrzJde758j11HvP3ndstEWDbroHu7+VQODEgAAQGYpCFVSfOoAJaD+Pp5hqttJFwfWoOJfKmV/FzmWe+S/fA7hehiYAAAAMktAa0KG57SbYZoyy4IhT0EvHisSnYZ7qfyn6hiUAAAAMk9Qs92M0hU9dfHwLhz9p6LH9jqiRnvX4/93FZ/aEoMSAABAZvFrQTI6v4hnlGrIev+WjGCHIU9eKxZEvHj/J5SA2gADEwAAQOYoCFUnY3OrW8W/3qMN8RC8/5Q1ZLzh3vAnoE5T/GoVDE4AAACZI6DOIKPzx3hG6dKuuli/JCID2GDEk9czBx3RrJfr8f//U4JqJwxMAAAAmfL8K5GXyeV+X4xnkLhYzeSZpnj+CAx4qtq5IiLqd3bN/T9Oz6UxBigAAIDM4AtfQt7/9ng5/5VIvoGG+MZmpP2lQ3NClqje3qXyX1ALY3ACAADIDEG9Chma4aS4Of81yVjNsxD4lw6dPeyIHiMNuamK85n/UAmqvTFAAQAAZIaA1pD0jFs0epfhhnj6AAL/0qE7ttji+gGu9/+PK74wjv8BAABkbAOwhIzNf+N7/7o4vBZH/+nSuiUR0bhb3A3AR+T9b5exGQAAAED6jX+4LRmbf7kF/k2fbYmXjsFwp6v876y5lqgSv/vfH5WAOgEDFAAAQPrxa5eToXmU9Fm8DUD7oYZ4EDn/adMpb93//lfxaVdikAIAAEgvvlAN8jAXkaH5WzxD1KirLlYviiDwL426daMtWg803NL/nsAgBQAAkH6CWl/SD2LGpkRDVK2dJkZNMcXp/fD+06nty23RsGvc+/9PlYB2MwYpAACA9OLXmpGBOeFW7ve6frq4fZMtXoPRTptePlYkFkQsUbmNFj8A0K8h/Q8AAEA6jX+Yj/4XkJH5OJ7xr91RF4ucCIx2mvXkfkcMn+R6//93pSBUB4MVAABA+ghofcjA/Nkt53/AWFP2qofRTq84mDI42C3/X30ZAxUAAED6COqNyMC84Gb8m/bUxYktyPnPhG7ZaIs6HV3b/+7EYAUAAJAeCmTU/yYyMJ/EMz4c+LfQiYhXEPWfkfz/NYsjbsf/rMkYsAAAANJDQB1FhuV3bsbnhgmmOLUXUf8ZCQCkTdXEGaab8f+Q1BIDFgAAQGr4QpXI+Hcio/J6PMNTqY0mgoMNcdsmHP1nSi8cLZKZFS4bgDdITTBwAQAApOr5X6EE1TvdUv4addPFioU4+s+kntjniBrtXTYAAe0WUn0MXAAAAKkY/5pkTJaSYfmn273/pBmmbFELQ5057Vnp4f4/oC6WqZoAAABA0vhlyt/bbkan1UBdPLIbxj/TCquW2waAAzTHymsbAAAAICkKQrWVoPp9N+Nfs4MuDq7BvX9ZqPdo1wJAfyD1wuAFAACQHAH1EiWgPUbG5PN4BqdWB00sKbJw718GevaQIy7r7hoA+Aw9txYYwAAAABInGK5PG4CNZEz+4XbvP26aKZ46gKP/stCR9bZo0MV1A3BM8YcbYRADAABI0PjrNZSgOp0MyW/jGRpuRNNpmIFqf2WoIsuSJy5xnstnpJWKL1QNAxkAAIB3CkKVFL/ajTYAb7gd/TfrqYtty5DyV5YaMckUVdrG3QD8jTQXAxkAAECC3r/Gdf7PxTzJuPf+8yMWGv2UoZ477IjOw10DAP9XCWj9MZABAAB4x681UALqE24R/3zvP3OOBaNcxjq+wRbXulcAPKf41eswmAEAAHg0/mpD8hxdm/xUaaOJvmMM8cxBBP2VtdYujojG3Vw3AA8rQb0BBjQAAAB3gnodJagWkfF4z8377zjMELdvssVrt8Agl0cBID59ifN8PibtwoAGAADgxfjXIqNRGIv4/yKe8b9+gC72rrJlNzoY5LLP/x8x2bUD4F+UgKphUAMAAIhPQaiy4lP7kuH4qZvxb9hVFzfNi4iXEPRXLrpvhyO6jnANAPw/JRgeiIENAADAzfgPUgLam27H/pd00cWqRREY4nIUn7xc0dP1/v8nik+7FoMbAABA6fjCncj4/8bN+NfuoIk5hSaMcDnq1VuKxMqFEVGjfdxnxSc4L2BgAwAAKJ2A2pGMxVNuhX7qdNTEjDmmOHsEEf/lqXP0+c8Nud7/f6YE1QMY3AAAAEoz/h3IWDwZixgv1aBUbauJ0VNMcWofjH9569ReR/Qf43r//18loOkY4AAAAEoy/q3IUDwtjUW8XH8y/oPGmeLBnQ7S/bJA9+5wxHXuBYA+UnxaTwxyAAAA5+GAv4DajozEt9zu/Ku308TISaZ4cj88/6zpALjOdjP+0R4AAAAAwAXGv4riVwcoAe0NNyPCnv/wiaY4DeOfNeJGSwtty8MGQH0Jgx0AAEAUrvDn18aS8f+BW54/B/zxnf/je2H8s0lcd2H4JNN9AxDQ9mPAAwAAKK7wFyb93K2zHxv/2SEE/GWjnj9SJAr66u4bAL9WiEEPAAAVHZ9WQwmoZPzVt908/7qdOM/fEk8dgPHPRp2mTRlfzXg4AfBh4AMAQEUlGuzXhHTQQ9CYuLwHKvxluzbeFPFy//8LUlNMAAAAqJBef6ia4le7kfF/wO3In1v6cl/5dUtg/LNdM+Z4CQDUTtFzb4hJAAAAFc74a7XIAIwjQ/BN0ifxjEXNDproc6Mh9q+2ZYlZGNnsVnCw4eX4fyOpNiYCAABUJFqFLyMjsJr0K7fSvnU76WLSTFPcu8MWr8D4Z724FkPjbrqXE4DJSlCvjMkAAAAVhaBeQJ7faTIA/3Rt6tNRE0URS/aVfw3GNSe0Z1VE1O/savy5m2MvTAYAAMh3fKHKSlC9lAx/hBb+d10r+7XXRIv+hrhtkw2jmmOaW2jJ5+fyjJ+XJZ4BAADkMa3Ctcnw96NF/3bS+/EMQ6U2mrisuy4mTLfEw7uR4pdrevlYkRg4zhSV27je/x9V/LQhBAAAkKf41QLy9NbSov9jLyV92wwxxKqFEfHMQRj/XNSDO23hH6R76ACoLpUZIAAAAPIMX4i8fnVCrIvfv73k94+YbIo7t9iyjCyMaW5q76qIuKqX6wbgLSVIYwMAAEAewUV9/GpbWuTvjd31f+Zm+JuRwVi5IIKqfnmghY4l6nVy3ex9SwmGO2CyAABAPhBUayu+cDsloN1Bv/7QzehXjt31T5ppiUf3wPDng144WiTGTnNtAMQlnh9Rgjru/wEAIOcNf0DtQl9Xkt70ctRfo70meowyxPblERz355E4aLPXaNcCQB+RtmHiAABAbhv/7mT8N9GC/n0Z2OUhyI9L+YZVeP35qCPrbPl8XcbBO0pAm47JAwAAuWn4/WT4N9Ni/gPSx168/gaddTF5pimOrrflUTEMZv5p7ZKIPN1xGQs/pw1AEJMIAAByy/A3JcO/kRbxn5I+9GL4WV1HGOL4BlucQTW/vNW5I9ECQK73/wH1GSWoI/0PAACyGl+oCi3YjRS/2om8thNegvuKi/nU7aQJ/yBDbFtmi9dQvz/v9cgeR3Qf6Xr//wmNoaWYWAAAkLWGXyPDr7WgBXsSbQDuoq//8urt1+ukS49/oRMRp/fjnr+i6MRWTw2AaAMZ7o0JBgAA2UZBqBp5++1llbag9iTp714Nf832mugy3BA3FUXEQ7tg+CuS+IRn14qIl3HyJ8UXqoeJBgAA2ePx1yPDP4IW6GOk/yH9x6vhr9Im2rTHsSxxcjvu+Ctk/f/jRUJVLffxElAfwWQDAIDs8PjrkOGP0ML8LZme5SGV70IV9NXFzfMj4r4dDiL7K3gBIA/3/7wBsDHpAACgPAhqdWgRbk5fR9DXE4nc7Rd7+5zOFxhsiGVk+F9FcB9EenK/I2p20N0LAPlUHyYhAACUFdxxLaA1J4N/Ay3C65Wg+qNoNLZ3w89q2lMXA8aaYs3iiHgaNfuhC7Rpqaf7/9dIjTEhAQAg496+zp7+BDL+q+jr4zIAK0Gjz5X7mpHhHz3FFFuXRaSnB4MHXayJM0wPx//aHsWv1cHEBACAzBj9S2ixHUne/i76+hLpD7Ha6wkZfm7Uc10/XQZ2HVhji6cPwvBDpatFf9fj///SBmCyTC8FAACQRgJk9IPkYQW1N2LBfAkb/WJxLfeb50XEI7sdWd0NUf1QPN230xENu7puAH5JY7QrJioAACTv4deghfRyxa8FyMufRrpPCap/TtbYy/z9Dpq4spcuBo0zxUHy9jmlC4YN8ioOBq3d0fX4/yEas1djAgMAgFd8ocpKIHwpGfq2ZOg5T38BLaan6et7qRh91iVddNFhqCHCYUuc2ALDDyUuzgK5caopqraNO9Y+J22kzWstTGgAAIhHQaiq9JYC6ohYRb5bYxHUf5XNVFIw+hzUx7n7HNS3fAEq9kGp6dReR7QZ4pr//zfSbExsAAAo2ejXIs++Dy2U8+nrN+jrC6RfJ9JxL56qt9NEYJAhFtiW7MrHQX3I4YdS1f7Vtriqt+v9//eUoNodkxwAAKJH+9WUQLgNLY4qGfzb6Cvn5r9F+oD0aTqMvmzM01kXwyaaYvvyaFDfS8dgtKD0aSFtKOt1ch2Hjyr+wkaY9ACACmbo9VoyaC+gXksLYT/SPPr1/aR302XkL2zBW6uDJpr20EXPUYbYvDQinkH6HpQhPXvIESMmme7d/wLqJiwEAIB89+oV8nTqK0G1JRn93rT4jaOvK0iP05/9Ipnqe15Uo330Xr/fGEMYGgf0OeIVBPRBGdZdW23Rfqjh3v0vqE7G4gAAyEcPv47i1zqQlzOOFroltOAdIT1L+nkqufhe7vS5UM8NE0wRMSxxcK0tzhyCtw+VnbYvt0Wjbq73/z9VAoWtsVAAAHKfoN6QDH1XMvgaefb7aYF7gvRd0v+lK2AvntHnimtTZ1li9aKIuGWjLZ7Yh2A+qOzFsSS2acmKkXHG7Bc0T84qvlANLBwAgNwjGp3fm3STDGYKaj8mvUn6O+njTBr84rS9lgMMMXOOJQ6Rl//IHkc8d7gIR/xQ+ab/0caTC0e5jN9PabO8BYsIACBbDXwlpbVanQw8efba1aQAaRZ5LkdIb2TyGP9CcSGV+p11cXkPXfgHGWLcNFOsX4LmO1B26hubPR3/f6gEw4OxyAAAsgdfqDp5JleQge8ka+gHtAWxYjvflk1LysDgs2ffmBZQ9u67jjDEmKmmWD4/Iu6ghfX5IzAwUHZX/1u3xFP73z/RXGuIBQcAUN5GvwEZ/W5k9GeS1tPidG+scc5fy8rDb9Jdl1HTnJdv6JbYcFNE3LIB9/hQbunFY0WykqT7uFdPYeEBAJSHwa+qBMItydhPIW2PBev9INYp75OyMPhX9NRFnxsNMWeuJVYtjMi2undvs8VpHOtDOayzR4pEs566+zwIqIuxEAEAysrocw5+f1p41pFepkXod7GmOR+mWkPfPRdfFy37G2LqbFOsJGN/60Zb1tlnY88tdRG0B+WLjm2w3aL/o/KpnbEoAQDSbegrK/5wXTLyzWihCZKWkc6S/pXJO/s6HTUZ+MStc7mu/vhpplizOCI76b1wFIYBqhiaNMPT8f9PSU2wWAEA0mT49Ua0uHSNHetvI72QqVQ8zrnniHwO0usyPBqkNy9iiX2rbVlTH3f2UEUUn2ZxASoPx/8nSPWxaAEAkiegNaCFpC95E0X069tpcfkh6T+ZKKd7dW/9y4h8x7TE5qW2LLbz+F7c2UMQiztJNujsZQOg2UrrcDUsYACAZAw/l9ddSoafi+/8L+mf6b7HZ4Pff4wpdM0Sm5ZGxNH1trhvhyOeRQMdCCpRYdWSm2WXufV3mruDZI0NAADwaPQ5N98go/9UrLQuG/3P02Xwa9LC1WOkIUzDEsfI2D+8y5GFdvj+/jUc6UNQXD13yJEnZJXc59q3aR4HsaABAOIZ/Bq0ULDRH0K/vjdWXjdtVfU4Da/DUEPMnGuJI+tsLOIQlIJ4DjXv4+n4/7jiVxthgQMAfBVfqJLiDzcko9+dFop5pGfTUX2vWrto3n3n4dEyupyKd/8OW7yM9DsISkv1vyLLEnU6um4APqI5PV8pCFXBYgcAuMD4a5eT4Z8UK7v7/9IRwc/V9freaIjCsCW2L4+Ix/YgQh+C0i2+Khsy3vAyJ39FGobFDgAQJag2Ja/AooXhFOkPqRr9Bl000X+sIeZHLLF/jS0e3u3I9qRYqCEoc8V/ru+ve5mfLyh+rRUWPQAqOi0KL1H86iLy+r9LC8P7qQb0XdNHFwvtiDix1ZYeCYw+BJXN8f/SeRF5zeZhnp5QfBrS/wCoeEf8oUpKIFyfjH6QPP6V5Pn/OVljz6VGOd+4BXkdU2ZZsv0oyulCUNmLm1V5PP7nTf4CLIQAVDjjX8ileQeSdtEi8GYqBXkK+uq04Jhi9aKIOIUiPBBUruIW1Vf09HT8/1va+PfDYghARaGAu+6pfWjy744FACVl+Ot1ilbh01RLHFpri7OHYfghqLzFp27L5lte5/G3lKDeAIsiAPlv+CsrPtVHxn9DrDzvp8kY/rqdNNlbfPPNEVmF70Xc60NQ1oiLZA0Y66X5j/YZef+3YmEEIN+5vrAhTfZ1SlD9GU38fydTope76s2YY4rbNtrimYNI3YOgbNSpfY6o2cHTnP5Y8WtzsTgCkI/41Wrk7V9JKiLD/04yQX1cnc8/yBAL7Ajq7UNQDmiR7fn4/x9KUG+OhRKAfCKoV6LJfSVpNhn/lxOt2lelbbStbv+xpli1MCK9fSysEJT94uu49kMNr3P9B1gsAcive/7qZPRvpMn9AOmviXr9TXvqYuIMU2y5OSKePADDD0E5VfxnvS1P7bzNd3UbFkwA8gVuxxtU99Hk/nWihv/Srrqsx79vtS2ePQTDD0G5qOmzLa/Ff4QSCI/AoglAruPT6ip+1aZJ/VPZ2CORVD7yFqbPNsWtG6OGHy12ISg39egeR7S9wevxv/oW6SosngDkKn61vuIP91IC6vcSMfrV20Xv+GfOscRT++HtQ1Cu6zXSsgUR0bCLx+P/gHo/Cfn/AOQcQb26EtDakbbRLt7zPX/Vtpq4urcuxk83xZ1bkMYHQfkiPr0bNtH0fu3Hbb39anUspgDkCgWhSopPvZwmMHfpez2R6H4uCzp5pin2rrLFc4exYEJQPunoelv24PC4HvyNhPK/AOTYXT95/eqDNHnf9Wr4a3WIVu3bj+A+CMpLvXy8SCxyEgj+C2ovKgG0/wUgVzz/mjRpZ5J+7rV8Ly8GXKd/14po1T4E90FQfuqxPY7oc6ORSNbPQSWgX4KFFYDsNfrk8as1aafelbz+h2XZTo8ef3CwITYujYgXjsLjh6B8D/7j070a7T0f/79P6wnK/wKQ5cf9TaMlfLUfe4rsb6+JlgN0EQ5b4ikU8IGgilH572iRvOJLwPv/oRJUe2OBBSA7Pf9qNEm7k+f/Dfr6L69NejjA75aNtngJnfkgqMLooV2OnP8JbAAeU1qHL8NCC0C2EdTrkeEPRXt0e7vr53r9O1ZExNOo1w9BFU4R00rE+H9I2izbggMAsgi/2kQJqLtogv6J9LnbZOZCPkuKIuKJfcjnh6CKKI7x4boeCWwA3iQHYzQWWwCyx+uvrvjCPb1U86sUO+6fON2Ukb9YBCGo4oodAA76TWAD8B3FF0L0PwBZQUBrSpMyTMb/D17K93YcZohNSyO454egCq4zhxzRe7QhKrfxbPw/o3XmFiy6AJQ3fAcX0NrQpDwm03JcJu9VvXUxfY4p7t8Brx+CoCIZ98PVPRO6//er47H4AlC+R/5VaDIOUILqK7GgnLhefy/a5e9aacsdPxY+CILOHnbEpBmm7O2RwAbgXcWnNcQCDEB54lfn0GR82y3Qj42/qVvi9H5HvHIcix4EQVFxum+rgQlV/uP2v49g8QWgvLx+n9pc3sG5NPBhw+8fZIjD62wsdhAEfUXnjjhidshM0PjL9r8TsRADUPYefw2afP1oEp4ifVRqhH+baIT/2KmmuG+HI0t8YsGDIOhCndhii4K+eqIbAG4ZfgUWYwDK1vhXkztvTr/hKNw4xv/6/rpYNj+CMr4QBJXa9W9exEr07p/1IK1DDbAgA1CWBNQITb5fu03QgeNMcSvK+EIQFEdP7nfI+0/07l/7L61DYcVXWA0LMgBlAbfvDWhbaPL9xe2+f07IEqf2weuHICi+FjmRRPL+i/X/lKDaUXYXBQBk9MifU/z8tOO+L1773iptNXFtP12sX4KiPhAEuYtLfjfrmfDd/xfkiBymdelSLM4AZJJguIpssxlUn43XyKdGe01W8EKUPwRBXsS9PgzNkmtHghsALjI2B4szABnfAGgjSa/Fm5DV2mmybe8DO3HkD0GQN9273RGBwYbsBZLgBuD75JD0wOIMQCYJqONosv0k3mSs31kTOu3iEeUPQZBXcREwy7BEnY564rn/Qe1hxRduhAUagMwZ/zE00X4q79tKmYgNu+oyfee5wzD+EAR5F2cHcWGwJLz/D8n736wUhCphkQYg/YafC/xMp4n2u3j5/Rzst3057vshCEq85v+suWYynj/r90pAG4aFGoD0G38u8DONJtmv4k3Ca/roYtuyCBYzCIIS0mu3FIlDa+1EO/5dqB8prbWrsVgDkPYNgDbcrcCPf5AuttwM4w9BUOJ64WiRGDUlae+f9YpSEELxHwDSSjDcIRpdW/rkazXAEHtX2TJ9B4sZBEGJat+qiKjbKWnvn8uO34XFGoB04tOa08Q6G6+Vb7Neuti4NCLrdmMhgyAoce/fEW0GG6l4/x8rAc3Bgg1AOuBIWn/4SiWoPlBaU5/igL8dCPiDICiFoj+mnlTRn69mAPi1cVi4AUiL5x++hHbUm2hi/bO0Sde4my42484fgqAUdOcWW1zXT0/F+LP+pfi0jli4AUgVv1o11tL3rdImXK0OmszzR11/CIJS6fY3bpopqqfm/QvpqLRSm2PxBiDlDUBhCyWofi9eed9ps02Zs4tFDMon8YZ232pb7FhhizOH8Hlk+uh/400R0ahbyt4/6wOlIFQVizcAqRLUTsQL+hs8zhQP73bEa1jEoDzSye2OaDPEkAZp+hxTpqXhc8mcHtzpiE7Dkqr4V5L+iIUbgJTu/UNVlIBmREtqltDSt40muo0wxN3b4PlDeVR97kiRmB+xZO+K4rE+c66FzyaDep42V1Nnmekw/MU6hwUcgFQIqJ2UoPqDkmr88y69oK8uc/2xgEH5ojOHHGGblri061ePobEByKx2rrBFjfY6NgAAZMe9v9aUJtFtpI9KmmA1O2hi6Tzk+kP5oxePFYmb50dkNsvF4x0bgMzp0T2ObPaTRuOPDQAASVPAR//qDJpE75Q2wcZMNcW5I1i8oPzqOsdFrEoa7/m6AeAN/LOHHNlytzx+/rkjjpgy05SBxNgAAJAdR/+tSa+U1t639UBD7tphNKB8EsezlGZQ8nUDcGqfI+/eVy6MlEsK76pFaYv6xwYAgDQc/ddSAtqW0ibWleQhHdtgI+IfyquucysXWqJK29JrXDhm/m0AeA4fXmeLS7tqomnPsp3XnPK3f40tWngs+MNVAet0jFYbxQYAgIx5/1ovmjzvlzSp6nfWZXT08zj6h/JID+1yRMsBpXv/DWjcL52ffxUuOeZBU60v3+f46aZ48WjZfeZ9bvQW9V+bDP/oKaaYPDOh8sDYAACQEL5QXSWoni6t2M+ISaY8MoTRgPJFfPdtGZb0LivaBuCZg464vv95D5yP4h8rg6s9rqcweaYpqrZ1N+R8+nIjGX/eMKxeFBG1O2ADAEBmCGqRkmr9c8ofe0h8RAijAeWT7t/piC7D4xef4ePxbcvyb+xzhcOLrz22Lcv8RmdxUUQadjcjzhuEUZNN8cju6KaEU47rdsIGAIAM3P2rPpo03y0p8I8n67IFSPmD8k8c/MZXW/GMydW9dbF/df5tACbN+PoRPAcEZvJnHltviyY9vN37DxhriqcPnD+RuGOL7fqsvlRAex2LOgBeaBVuoATUozRx/nvxRKrcJnr/BmMB5ePdf6/R7vnnXPCKg+XyrelOSd501xFGxoL+7tjsrcsfOxwjyfM/e+TiaoFOiTUaStH7WNgBcD3216vSZJlA+m1JE6lFP0M8vAv3/lD+Rf7vXhkRDbu6GxTuB/DQ7vyaAzfPt0rsuMcVENNdE4A/67u32qL7SEM6FPE+64ZddDFrriU3KCV9L5/3gkFoBgSAKwHtOposz5QW/MRHpK/g6B/KM3ERqzkhb1Ho7W7Ir7oXzx12RI9RRokpdZeQAU73e+WTluGTTFHTJYKf1xtds8RTB0r/+aOmmGgHDEB67v21GrQBuLmkZj8cgDN+mhl3MkJQrurxvY6n42gWe6751Alw90pbBjaWlup7Ymv65jx/blNmma7pe9XbacLULfH0wfg/O2JYXjcA/1J8Wkcs8gCUugEIt1GC6tslTaCOQw1xYostj+9gMKB807rFkVIL/1ys3qONvHnfLx8rEtNmW6WW3k33BiAUtjxF/Kuq5am0+I4VttcNwH+UYHgoFnkASvb+69MkebWkyXN5D11sWoqUPyg/xQFpXoL/iivQzS3MnyqAHIjXZrAeNwCP8+1T76pYJGbMsVxr/HMgInv1L3osQ8x9Czz2DfhYCWgRLPQAXIwvVF0JqCvkJCmh4A97COVRFxyCyib63xZ1Ouqeq9AtiORHESCO5VlSZMn3lMkNAAfwzQlZZNx114A/Q7ekUff6vc8eLhKtBnh6dp/QBmA3FnsAvhb4pw6nCfLLknL+8y3gCYIu1kLbco1GvzAwbfvy/NgAcNzDoHGmawpeKhsAzttn49+gi55ywF9pMQVcHMjDs/uc9CgWewC+Yvy1ljQxniB9evGkqUc79r2rcfQP5a/OHnZEZ5fKfxeKy+Pevjn35wQ3+Tm01nbtvJfKBoCNM6fwuRXr4QDjsdNM14C/0k4xFjmeAwG/rRSEqmPRB0Ae/Wv1aQOwmSbGRyVNmMJCK6+inSHoYnFBn8t7eG8/25T+bSJH1Nkqntcz55iu3fQ45mFeJPGYBy7Sc8MEw1PA38BxX63wl8wzrO4tDuDHtOZdh4UfAJ9aTfGrc2SBjIsmCkdDDxxriMf24ugfyu/gv+mzTa/GQ+rafnpevPcHdjqux/LFMUBTZ3vfALwSq/DXc5QhqrRxr+3ff6wp7/FTeS/37XBEYLCnIM63yeGZgMUfgIDalybE77/W6IcmLXcEy7dSpxB0sR7eHT3+92r8WVySNh/e+1yPRY8S2QBw62DukdBxmHuFP3YyuMzw3dtseR2RynvhuIHR3goC/YM2ADdh8QcVG7/anCbDayVNEi79uaQogqN/KO+14aZIIrXkpUwj91MAn9jvyH4GXt4vG2ovmx6OpbhpXuQr7YRLE28O2GM/Qk7Gq2moK8JNyfiawkMdh0/J8TmMksCg4hLUGylB2ejn05KO5Hgn/cxBHP1D+S2+x+ce9F6L/xRr18rcPxlbsTBSYt3/0tRtZPzCR6f3ObJr4KVdvW0qLuuui7WLI2lNLebn4jGW47TiU5vBEICKB0fABtWNsi52CZMjMFj/stc2BOWz7trqyKY+iRh/Vq4HAJ6h199pmPesh+JU4OdKed+3brRF79GmqNnB2/fieAuu8pfuE8aT22z5vjy8hh8qAbU3jAGoWLQO15H3X9wWs5To5ju34N4fyn9x6tiy+VbCxr9Ffz2nC2JxGe+VC7x1PLxQ1w/Qxcntzle+z+n9jnAsK6HvxUf/g8Zlpozy80eKZCqhh3oO79M6GCJnqBKMAqgoAX9c6W8GDf5fl1aE4+b56PIHVQxx0BhHqSe6AeCiOS/n8Bxhoz14vOm56NGFR/Ybl0ZigX6OOLDGFjdMML2W4P1S3GzpwZ2ZO0FZOi/iKbOBtF3xFdaFYQAVZQMwjQb9b0qaDHx0N2027v2hiqMj621P+ekXK6xaaQlaK6+Ux01kxJt01xN+3xwvMHuuJSP2uVrflb0S/x5cDIhjDzK5geL0Q28dHdUzpBYwDKACBP2FO9Kg/0VpebhDyCN4GPf+UAXSiElmwgaMtX9N6ilr5Rb5v8+R7ztR779YV/XWZSxAzfaJ/19eZ8aVQStxjivoO8bw8B7Vd0i9YBxAvhv/DrF0v89LyvfnIKi7tubuogZBiYqDXOt0TNyINSOv994dTs7e/e9bbcurvmSMv1wvYkrm/3LsBJcdLotW4kWW5WWT8oUSUJcqfrUGjATILwpCiuIL16JBPoX0q9ImQfM+uji2HkF/UMUK/psyy738bUniu3O+Q8/JlMeDjuh7o5m08U9F3GmQrw1eKqPYCQ5kvsRTHID6TVIjGAyQZ/f9WhPa3S4uLeCPxfeA+9HkB6pg+sZmWzTrmZwXbHGP+hwtjrVvlZ1QueN0iU8MgoMN8cDOsl1rOgz1FOD5Ea2THWEwQL54/tVoUPck3U76V6nGv4cuo2VfRsQ/VIF05nCRGD/dTMoQ1umkiS3LcrMFMKct9hpdPt4/Bw9GyqFyIq9vnl5jQNsKwwFy3fBXUfxqkHazW2hQ/6Ck+/4LPf9FTkScOwKDAFUs7SEv+Oo+yXn/rQYasuBNLr7vvfS+63TUy2UDwOmD5RFgzE3MuJW5h9f4a8UXaggjAnITf+F10Xa+Kkf5/0cGt5Qy2Bt20cUCOyILZsAglNJVbKcjbt1ki003RcRi57zGTDVlPfRENW22JRba0e+xcmFEHFxri9s227KffKYjoqELDMIeR+atJ1r298J2tY/nYGdMztnnbnvJRv6nqqH0mZdH2iRnA3DNBo/XAIUwJCD7Ceq1aLA2iXn7IRq8Z0ifeZmI9TprYm6hKV48VrEWfg764iYlT+53ZPT3yW2O9AQ11ZIGmrMguMqZR28hI+KIdI6S5uYoIyeZYsJ0UzacWbUoIrbcHBH3bHdk61Z+/ZzKxRsHbp/Ki1yu5qSXpXjDy6Vnk70Dr9E+ev+fi3n/y+ZHPAbEpV+86di5onyuTTjbYMdy20uhInKY1NeUlmEEA4KsOtavpLRUayt+rTkZ+y40SEfRYF1O3v5j9PWdRCbiFT11aVAqgvHn+85T5KndTl78jhW2rG7I/d4HjDVkgZAa7cvP0KeykHK5Ve5D332kIT2bWXNNaZR4k7CdFjo+WeAAN+6Lfoo2Cc/Rpuc1bA6keBw07Jr8589Fb3bnYAOgB3c5st1ueY1bvm4sz+JivGn22Ovhz9KhKghVhuEB5eHZV1ECejMy9u1oMA4hzSCDz8Z+L/360di9/geJTkA+7mw/1JAlPPO5xC97Oie22LLKGXt6Q8YbohV59bU7aDln7JMRV7TjLmitBxpywefCTnyKUBi2ZLzHuiUReerBm6KHdjvyRKSiGH/eGF3bL7VNHxe/eXRPbn1mfDo0PxIRdcvxZKvlAEOevJX3yY+Hax+OmXqS1t8CGCOQ/gC9VtoVik8PSAW0iSQuyzuftI4M/S309WHSOdL/xCr2/Yn0SSqTj4+0x041xW206OdjtD8bscPrbOGYlszP9g8ypMdRrV3FMPqJ5GA36qaLq3vrotVAXaZH9R5tiGETTTFjjiV7qG+4KSKOrrelx/j8kfzZHNyz3ZYb4JSi2Gk8TZ2Ve+V/793uyI1LeW9M50fK9+rk4BpbXOMt8PM9JaDOles1AHEMeh0y5J1JXciQD5RdpQKaTZpHA2g3DaQ7o1Jfoq8/If00lo//fzG9Kwdb1KP/N+nTdE88PiI+Tgs6F//ItztiXtT5+JtziznCmA1cJRj6xPOz20RTtDj+gO+I+bPkSndcHKr9Dec3CBy8uG15NHDx6RzpFcGnXRz5zgawatvUPiduLFNe99ipXINxNbxs2Axf2lUXyxeU3+fHV2Ec6+PhtXIswFO0hl8HI5fP+GiH59NqK361ERntpvTgC0itSQESe+cmfd1KXw/TYHgo5pX/mPSPbFzIOUCJF2++65pTaEkvLl/K+vL74N7rXKp4cZElfOTBllc0M3S+pntxTfjhE6NXDbZ5PmCR4xBOXhC0yEfnXD2PAxdZvCA/f7ToK3I7oWKDdvH/YRV/T4754J/FunubI43fJV3S83755OTpHMvW4FO/VEr+lqLPvAYcl7SJ4mfCgavlsTZxjExTr8WfAtp2pbWKLoF5c/zu0y8lY9+ajHkPesAjaZen0kNeRTpBv3825qV/kCsLMNe4btpDF75Bhug5mox+yJTHt+cO59edPucO71xhy/S7K3rqML45Jr524Lt3vgfmtrucRsexCVNnmbKjXrFUzRJLaHPH8RulaUHE+sr/KRafdPH37TjMkD+LVTPNQZ68wcmluXPuiCM/kzQa/T/FeoncSWvoK8meWHIQ68y5lgxSLevgVF4bB9HYq+LNefiA7MVYGM9cxV/YWHZ5CmgzSatJt5HOxgz933NpEWXvniOQOT2sFxn7KbMsGdjDnha3vTxzKL+Cufjolo/4+d6wz41GJryYZPQh6W3S7y8Qnwi9Sno5CX2P9NuLvh9//4+xccg+5VrxnzWLI+ko+fsR6dukXbSWzpAOFEfI+9VBsbGf9OkRbwY55uRcGcea8JVQAqm+NEfDLWFMc8XL96vX0+6UDL66J+bV/yiWKvffbF9guC55C/JcOHqbd+7cMjNUaMmiMXz3emSdLZtbPCQDtPI3WpuPbrlhCF9l1O5YJp89j43fyQUtoD1Euk9mXQS09aQ19OeTpQLkDQS1waQBF6g7/Zs2pGAS6kz/v99Xv5/K33/clz8zqOmx18HaQLpbvsag9gzph6Sf0ev6Owx0ZnVtPyOn5tx9O6JxD5VSuyb7EY21BfS1A62rdb56farVor/j4OW/pJoeOGqKKTdXZZWdxD0cBo/3HBT5Kc3J25Wg3hgGNnvv8pvQQ5pOC+EDsYX8L+XpRfHulvPM/QONLzVuuikmzIjKsaJGffUiTsmKyII0LDbsFxZ44TtvLtNbUQq8PLLHkbELfK9cKzNpe+/LOA6+8gloixS/NoPGTG/6Mz/pOlJz+vPLSI3p7+rTIldHxoiU69jWqsZeR1R+rZF8jUGVY1aukXErAbUVfeWCUD3p76eRCunfHCHdGtsEv0H6Gwx58uIUslyZhy8fKxKz5lry1DDJ9/sBjZ11ck74tJqljs2AVo/G4a5UnSteL/l0c/ikaKZSWXzOJ7baomYHz6cA/6T3uZc2AZfC2GbH0T5XwWtOD4U9pcdiZW+TGnh8j87HQRyhyo1xOECEDdC1faO51P3HmGLEpKg4j3pxUVRcDIQHK+uurY547hCKrCQbpXznFkdMn2PJu8EUF+rPo5NV+2Ms2+JZWqRWkPdyA03e5opSSTmvfKfS1+ULVVN84evp8+hDn8scUhF9Ridic+gHsbTT38U+v7/Fmkh9UtGNP2dG8AY9V67O1i6OiMbdkppLvI4+ReOjh/cUOBpXQfXBdJ6wdh5uiJvnWdIh4uJBmTgZ4O+52LFk9ovH10XzQD1OX6+itaQSjHD5eEP1yfC3Jy2jh/Ejr4sTR4tzEYxmsTt0PmLvP9aQ3cD4iP2medEKardttOVEP7UXddnLwvBzWdsFtpVqYN+nsSue75DuJ6O2jDzgwTRWmmHCJHyS1oA+N58SDA+RKa1BbRXpKOnBWG2K12P3vr+PpbBWiA3A0IlmuRaxSezo35EVIpN4n+/SM99Gxv+ahMdNq3CT2Cbgw3RWvOR1gR0vzio5tsGW/RdeSGMLZv5+XDckgRRJ3uTcQvanDRaLsjX8tWlw9qcPf2csIMX1YfEOuAsZ+rHTTBEOk5Enr53LgJ7YGj1ifwXtb8stqp+vOZbQ8+CdfpXkc7PfJD1BC89WEgd5tqWdeXVMlgwQ1BUloF8hNwcBjU8P+ORtLoljEvbTV756Kw6ufTufTg34Kopz13OhgBYbR46dSeLo/1c0h3Ty+pObP1yq3BduQYbx9tg1W1qfARtorkkxaJwh61FwTwMO5OPsoJdSKGnOGQh3bLFlQawEXxNvhsfQhrk2FofMH/fzwNoaW1w+jjdIuCAMe/U8QPavjtZC53t0NEnJkrtJWkTXL4mIbuSh8LFqEgFKHJH8rVgw3DDyVK+lSVgTk6Tcgm65R0Udmp9XklrTM+kRC5KcQL92pEcZ0O6NpY69lYsbgLZDdBl4mwvzi1OAuQ5Igu/xx2T8J5KqpDwW/Hw8ru3IZCo1nwzU76zLin4dhhmi35iok2fqloyp2nxB/YnSxCWhN94Ukf+H/y/HHyT4Or6IXZUdpvHdERUDM0W0TO5vYlXySnwYPBj4IXKZR+77zOlw8O6zsBzpDkdG3iZp+D8kA3OS1Jd0lYxI9oVwD5fdp3bV6DnVlQGVQZUNA2fndCQjwcbmZvrz20mvxuINstL48+nU7LmWDKrL/i6HTjKe7Ov0LPrTc0nfyVlQvUTWV4lWOC2z58QnNZwqzG3OuRcGXx+UJj4d5nWI/0+K1SHZIf0DfX730lgejkmfHqNfgxYJzt1/vDSPnx9ez1GmzCF97jDu67PZ4793uy3jLBok1ob0i1gmxxuyEVLrwmukhwHyM0jRF7qUNgy8OZgbrdehPhqrkfBrucAGtb/GgjvL9GqBM3mOrc9+758zhcZNtxK5TuNg2W8qwXDbzF0b0fOMlkD/V57HiPyHxusbMu4IpOo1qA3oA1Vjx/0l9krn2uR81IOo++wWl3zl4J3AoIRrsL8ju3Hxvb5PuwKTokLHHnBXzI60KZhFY2Ip6Ugs3oCr0H0/djr450z00GBjymlp545kfzAtX3kmmEHzU5pfYzJ+PdRa5TTV9aRfZuIZlbM+kbETAW2XjH+Ag5LyZG9MO6l9JR0d8b3P9f112fOc64rDwGa318+d+UZMNkX9zglNKPb4H6KFKSQrOAJQalwQ12xQu9LiO5rGzGzSStJB+v39sQCtn8TK1qbU+GfHcjvrA2q5OBhnNiVwrUYbbHV8Ga7rtennDSPdETvFyQfjz4W37pBxSJyZBlIdJOFgtNrS14/42HvktBa+409nCgiUgUI+ux1Zl503awk06uH82odJk5RA+GrZoAmAhE8PC+vK1M8ApzFqPWk8DaGv08ipWBRt5sUZI9oP6feeCiJxBtFzh7N/viWYxvZPev8LFL9arRzW+Kb0DHiz9kIuVGUtRf+m9/A8fYYT6f3gdDJNA8MXPfIt+b6fU8W4qx0i+bO95WpEdKJnxYE1CbTk/YVcpIPqZTD8IP2bApmexjFFl9Cifbms9MhtXj2Mze1Z7v1HU/7MRFL+2LnaS59FY6UgVD7P4/pwVfr5V8uNQED9Zg5tBP5Lr/d5Gjuj6LXzJrMyJlfqhr8KfaCdYzvCEnuU+wYa4uwRHPln8/0jl+8dP81MNJWPPTGTPLZ6mAigzGgZbublLpo7CWZz3j87Q1ztL4Fuh/yeT5Lnn0XFsSop9Ho60ev6Rqwh1t+TbTGcofv992QQKpfU9mmBilE9tEw3ANL4nyntIXBuJt9vwdBmn7iARnGQ3/UDEkrr+y1NqH3kBaCSFih7/NqKWAR83KIzKxZYZd6mNhFxjE0C+f6fy4yKgNo/S09pKit+WURIJ5twUvbqKJ/U0E9jP/ebtEZxtb9piq/wCgT3ZWwDoN0d74EMHGuKB3dhA5CNx/28AI2abMr+CR4n1z9iVfvGJV1tDICU1hv9Ei9VRNsPNcSje7L31JEr13GXzAQ23TT31Lk076rmwJVNLdqktYvVf9lGejSW7fFuLDU4nQb/i1g10W+R7otVtZyuBMLc7rgaJkymCWjheNXBuE0k1+y3TUuc3IaNQDaIiyzZZkTmRycQ5Me53AtoR32t4sPdGSi3E8dxbpkB3BiM+4K8lKWFfx6jjQmnJiYQ9CdonT1Km5+6Ofe8ZCEp7Rp6/V1o7Rgme1NEK0veQ3oh2rpb9VZsKKD+JdYW/tlY9P4WUiGNiUHR3jLaFfQZVcUkKdMHrNaMTcqfx3t43A+eO/TxZkDTLLF7ZUScQ1xAmYv7dfe50RR1OuqJ3KM9KKu/BbRaGPCg3OBTp6B6zK2QUOdhhrhne3Y6G2cOF4m5hZbcpCTg5f6M5t6VefEMryusImOGOIiRA/Fk6261pWyDXayA2k+2+L7wz6J/3ioWAHoF/fpSWaGyRSGCjrNkZz4oVvUroQCQep114R9kiL43GmLcNFNMmJ64iixL3mNz/eiXUT64xGCj+3c6Yk7IktUXE+iY9XOaiHMQOAOyZI3pHmt3LOKVFF9K3n+2nrxpqiWqt0vI+L9Lxm6ovGMHIMsn6LBYN7FyifrkE4ZT+3CqcKG4idK2ZZFE6ot/EavKdpc8VsPCA7LjKLmGbBEdp58IX2f1G5OdLX855oavQRM0/h/Se95Bm/CGGAAgRzYBsh7AvbK2chlvADjjACcA5xcc7qY1bXZC9fs50vj/kRxadC7HYAZZQ7Qw0Atu3v/6m7LP+y/unnlJl4S71XH3xfZ4+CDXJiu3FV0a7U9ddhuA/rT7h/EvEk8fcMS8iCXbKifocdyvBNUeSlDHXT/IJu+/Oq0pZjzvn9U1C6v+sfFfszgiruqtJ1JYS8RO4Qyai8i2ATkGV6jyhWvTJqAdGZTdsfSxjG8ANi2NVHjjfyd5/b1HG7LhUgILzge0wK6XUbQAZN2pIkd3c8vb+OOYA1yz7RSO+9XzyWSCrbM/o7XzEZqPdfHwQY4j24Q2UfyaTgP6gVjZ2N/HdrjvlSJO8/m/WJewn9Jk+K68D4uX93uDLidcRa3kd/8OR8yck2BqUfQzPSujbgtQwhdk7YnivHjjmI3rxBlmVpUZf5Hm5KqF3N0vKWfml4pPa40HD/JwN69fovhVLhIxjjS5FA2nCRBUfOGrletDNWlCrIo3YZrRDvvQWlu8VgGj+x/a5Yib5lmi1YCEcvpFbJO1m55FcwxKkLX4tIYxp6HUsVzQVxd3bbWzyvPnVueXJmf8P6INeRgPHgBfqLZMQ4tWkCpxwnAVOy76UdE6DHINhXVLIvK4n2ssJLjIcJnOufT54ogRZLv3vyBe2V9uWsXxLtky//nOn+dl4+56cleZAfVxpWW4AR48qOg7/8toMqyNlXkstdc3FxV65mDFSf17OVbClyuJXZb4IsN9vE/QotqDNlY48gfZjV/rGMtKiRv4d9+O7Jj/Lxx1xMqFVjIBf8X6P5qbgxS/isIboELv+q+TXa+iBqvEyVK3kyYW2JGs7/WdzsY99+2wZeGjK3rqokrbhBeXd2RPdb/aVAnqyO0H2Q1X/Quoh0prL87itDou+pMNsT/njhTJgmSNuiYc8HdBq1ptudJaRQYOqLCGv6FMfQlob5c2Uaq25Ts/QxytAB0G2ejzBofvN8dMNRNpG3qh/kML6VMIKgI5dPrHLcZnxusxwusAz4kXs6De/6m9jgxCTDDl9uIOdvdkV5tfAMpuwnPKYA/ZvjFOtygu9DFkgilu32TnveHnamb7Vtti+mxLHvUncaT4uazDENC2Ky3DqCQGcge/dj2N26fjjW9uZMWFrsp7rt6z3RGjJhupdrPjWv9D8OBBRTvmq0S73qtoAiymCfCT0voIcHQ7R/pyKc18L/X7BL0/7mnAd/yX99BFleSOE7lgymn6TEfR54sjRZBLxr8WjduFNH7/FW+MLymKlHukP8fidB9pJJp9c7H+Jd9vLrT5BSCtcJOLoPoMTYK/xpskIyeb4uBaWzx/JJ/T+Wyx0LZEr9GGNPwpLCh/oQVlqfSiClDHH+TaaWC4Na0JP3cL/OMeF+U1X8/SOrR8QURcP8BIJhbnYt2h+DRE/YMK5fnTLl/l3P4/xkvxadxNF4uLLPH0QUcei+ej8X9wpy2mzjLlCQcHNlZKxZsIqGfI4+9Bqo1BBnLUKbg73prA14B7VkXKreYHB/uFCi35OiqlXL1U/T1t1q/GQwcV5HhPrU6eaU+a5M+W1tObDSDn9o+fZoqHd+fXcT8vWmcPF8n3tW5xRHRL/fgwWjiEqyX6VZs8CeT1gxz1/ENVaF2YFs/412ivyWvA54+WT7XNe7bbouMwI12ly9+m9zuY3jdS/kCF2NnXjE3wH8SL7OUJxlW0zh3JryP+R/c4YvdKW8yYY4rmffV0HB2KWKnkw+RFdMAAAzm+PvQgj7jUin8cC9N3jCEe3OmUeUAux+WsWBgR1/ZLh9dfnJKrWbRhR3wOqDATXI3V9y81p3ccef0cVZsv3j535Tu4xpZeS/+xhjzZSJP3wDETj9GCOQbV/EDunwxqV8ZaiP83Xqvv7csjZVrvnwP9jm+wxegpZjKtfOMU41K3K8HwpXjwoKIY/2nxcnqb9tTFIicinjqQ+8afjwo5TdHULdFjpCHv9mu2T1vHQ1og1ddJYVo0m5MHgeNDkNv4QjVofXBk8Gqccr98716WQcAvHnXEkiJLtBxgiKrt0jZ/P6a5e5yEe39QUXb3apt45Tw54n3lwtyu5c9eCd8PchR/5+HRKP7aHdLe7vhPtHCotFheRd4DeoSD/CCodSX9MF79j8Bgo0zTfx/a7cg03Pqd0z6Hz9AcboSHDiqK8efd/W2lBfzV7aSXez5vMlHATx5wZBe+XSujpXmv7q2ne6EoLhDC+fw/VwLaeuX6QhTzAXl2MqgV0Ph+Nt48qEdrxJ1b7DLpscHxBbpmiUbd0j6faf1TX1JaFjbGQwcVaQPQiQb/G6VNjCbkKZ/Yamd1Rb4zhxzxAC0MfBe4dVlEhMKWGDDOkC2I0xTIV5L+QXqRtE7xqT7k84O8gwvfBLQd8eZBzVinv0ynAHOQH+f1t7vByNBcVh9W/OFWsvAZABXoeG9ivG5+9TpF7/Z2rrDFMTKwD5BX/XQ5xQHwMT7HIJzcHg3cW7skIu/xOR2xxyhDRu5Xa5cxg3/hYvG8ElCLlGC4BQYQyGPnYCyN9w/izYcBYw1xen/m1gPus7FjOVfdNGSKYQbm899Ie2hOX4MHDiriBmAu6b3SJgjn/PM1AEf4Xt9fF+2HGrK05pDxppgy0xJh1RIL7YjYuDQi9qyypXEuVjKFQHhzce8ORx4pbqLvuWpRRFhG9OcMHGfKnx0cEg3c42PAqm0zbvAvXChOkkc0iwy/jwSPH+Sx8Zdtfv8n3pzg9eAAbcQzEfXPx/376XuPmmLKk7w01OIoSbTuqctoTl+OBw4qJgGtH02E/0108nCuLXvbfATI1fE4BYcNMrfBLda1ZKQ5L/dCcYOQNoMN0Wqg8bW/Y/FdPf9fDtLj78nVvGp3jP6cMjL0F1fu47K9++krF0dqrPg01AMHee4U6I1p7N8X64BX6r0/H/2/lIFOf+w83DDBlFVGM7jB/5ks8hMM18EDBxUXX6iebHMZZ7JXMH0YS4c8Q4a/UPGrDRQF14KggtA6XI/G/dpYjEuJc4Q3/tzml4/n0+Xt8x0/H/V3GmZk0uhzoPPvZfdNv4ZgPwBipwA9aGJ8pwIbfV4Y/kB6XgmqW2Qp5IIQ0vhAxcKvVae1YCrNg9/Fmy8dhhoy6Dblhj20gTix1RFL51kyhqdWZk/5/kS6n+b3EHJ6auJhA/CVYz91EE2QVyuY4X+LFrxHlIC6gTRB8Yeboe43qLhrgLz3/2G8OdOgiyb2ro6klLXDcT67VkbE9DmWaDPESK25lrv+Q3P8FH2dqfhw1w9APA+gQzQitvSgwBzXZ7GMhwdpw7OENJje8zVk9OHtg4pNtPvnabc5VBhO/t7/5DZbxg30vdGQQcVVM5uxwxU5XyOZNMcLUJETADfY+w2o9WnH3J8mzuF494A5pp/SezpAGke/bkHv8TLFX1iT3i+eOQBMtPX3J/HmERvuR/YkdvTPabsrFkREvzHRaP46HbVMe/wcuPtLWYobFTkBSJZKvCFoQkYzIvPeOXgmqP09S4MFP4ltVt6Jdd/7Jmk/7fwn0M6/cTSIDw4AAF8jqHOxn9lxU4FJ/kGG+MZmJ+7RPlfg5GC++3Y4snQ4p+zWaK+X1cne38jgf5cMvkGqggcLQPpOBmoofrU9LRQmTbTj0WA5eVf4ZqwU7hdlZOi/iBn6t2T53aihf4x0jLSIJv5o8uyvwT0+AB7g6pUBtTvNne/Hm3eNuurSi+fOeyVF79+2KVqzgwuGdSOjX6dTmW7+OXj3UenxB8NN8VAByLjXwK1Bw5w5MIm0kDYGW0gn6NePk14m/SR2YvB2gpP537FNxe9j34O/11P0ve+mr4dIa2NdySbTn/H9fSvl2kJE9AKQDH61Oc2n++Md/XOXzOmzLfHsIUca/Mf3OrL4z4qFUYM/dIIhu/FVb1emRv/jWPOyW2gdmIjgPgDK15OoSpOwCS0oBTQhgzQxeXMwgDRYGmvvGkMaJP9vQOspv1dAayEnuK+wHu7sAUiX8dfq0txaQ3Ptn/GMLRfm4uY7c0OWGDLBlJ00m/fRRYMuGavO5xLYx5lK6mLauHRT/OGGWBMAAACARAhqw0jvuxld9uy5GifX4a/UptxifN4ng38qWrlPnj7WwgMEAAAAEqV1mDNh/pzFWTv/jt3tP0WvM6T4tEYI4gUAAABSwa9dQUb1sSwz+F/EriK4J8mzSkDbQF5+TzwsAAAAIB1wCdyAutLt3r+M03c5m4eDfIvotfVVWocby+wEAAAAAKSJgDaSDO0vyjBttyR9GkshPkCarQTVXopfRfoeAAAAkCHj34IM7hOxojnlEb3/nWijLbUbfW1Or6eBEtRRsAcAAADIGD61oSyFnXlD/3nseuFPsaN9ztOfQob+MlTjBAAAAMoavzorg309Po5V5vwW6R7y7m+mnzeEVBsfPAAAAFBeBPXGMW88nUb/L6TXydifiDYRUsnLDweVglA1fOAAAABAVnj/4eZkrD9K8Vj/vMGPVuEbTl/bK4FwE8UXqooPGQAAAMg22EAH1DFKQLuDjPjv4nfzVH8WLbWrnaR/v1vxa2Y0aE9rSeLWuo0Uf2ENlN8FIHf4/w+oru9EM7nVAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDIxLTAxLTMwVDA4OjE5OjEyKzAwOjAwo2HvPgAAACV0RVh0ZGF0ZTptb2RpZnkAMjAyMS0wMS0zMFQwODoxOToxMiswMDowMNI8V4IAAAAASUVORK5CYII="; - private final static Integer IMAGE_1_PORT = 3306; - - private final static List<ContainerImageEnvironmentItem> IMAGE_1_ENVIRONMENT = List.of( - ContainerImageEnvironmentItem.builder() - .iid(IMAGE_1_ID) - .key("ROOT") - .value("root") - .type(ContainerImageEnvironmentItemType.PRIVILEGED_USERNAME) - .build(), - ContainerImageEnvironmentItem.builder() - .iid(IMAGE_1_ID) - .key("MARIADB_ROOT_PASSWORD") - .value("mariadb") - .type(ContainerImageEnvironmentItemType.PRIVILEGED_PASSWORD) - .build(), - ContainerImageEnvironmentItem.builder() - .iid(IMAGE_1_ID) - .key("MARIADB_USER") - .value("mariadb") - .type(ContainerImageEnvironmentItemType.USERNAME) - .build(), - ContainerImageEnvironmentItem.builder() - .iid(IMAGE_1_ID) - .key("MARIADB_PASSWORD") - .value("mariadb") - .type(ContainerImageEnvironmentItemType.PASSWORD) - .build(), - ContainerImageEnvironmentItem.builder() - .iid(IMAGE_1_ID) - .key("TZ") - .value("Europe/Vienna") - .type(ContainerImageEnvironmentItemType.PASSWORD) - .build()); - - private final static Long IMAGE_DATE_1_ID = 1L; - private final static Long IMAGE_DATE_1_IMAGE_ID = IMAGE_1_ID; - private final static String IMAGE_DATE_1_DATABASE_FORMAT = "%Y-%c-%d"; - private final static String IMAGE_DATE_1_UNIX_FORMAT = "yyyy-MM-dd"; - private final static String IMAGE_DATE_1_EXAMPLE = "2022-01-30"; - - private final static Long IMAGE_DATE_2_ID = 2L; - private final static Long IMAGE_DATE_2_IMAGE_ID = IMAGE_1_ID; - private final static String IMAGE_DATE_2_DATABASE_FORMAT = "%d.%c.%Y"; - private final static String IMAGE_DATE_2_UNIX_FORMAT = "yyyy-MM-dd"; - private final static String IMAGE_DATE_2_EXAMPLE = "30.01.2022"; - - private final static Long IMAGE_DATE_3_ID = 3L; - private final static Long IMAGE_DATE_3_IMAGE_ID = IMAGE_1_ID; - private final static String IMAGE_DATE_3_DATABASE_FORMAT = "%d.%c.%y"; - private final static String IMAGE_DATE_3_UNIX_FORMAT = "yyyy-MM-dd"; - private final static String IMAGE_DATE_3_EXAMPLE = "30.01.22"; - - private final static Long IMAGE_DATE_4_ID = 4L; - private final static Long IMAGE_DATE_4_IMAGE_ID = IMAGE_1_ID; - private final static String IMAGE_DATE_4_DATABASE_FORMAT = "%c/%d/%Y"; - private final static String IMAGE_DATE_4_UNIX_FORMAT = "yyyy-MM-dd"; - private final static String IMAGE_DATE_4_EXAMPLE = "01/30/2022"; - - private final static Long IMAGE_DATE_5_ID = 5L; - private final static Long IMAGE_DATE_5_IMAGE_ID = IMAGE_1_ID; - private final static String IMAGE_DATE_5_DATABASE_FORMAT = "%c/%d/%y"; - private final static String IMAGE_DATE_5_UNIX_FORMAT = "yyyy-MM-dd"; - private final static String IMAGE_DATE_5_EXAMPLE = "01/30/22"; - - private final static ContainerImageDate IMAGE_DATE_1 = ContainerImageDate.builder() - .id(IMAGE_DATE_1_ID) - .iid(IMAGE_DATE_1_IMAGE_ID) - .databaseFormat(IMAGE_DATE_1_DATABASE_FORMAT) - .unixFormat(IMAGE_DATE_1_UNIX_FORMAT) - .example(IMAGE_DATE_1_EXAMPLE) - .build(); - - private final static ContainerImageDate IMAGE_DATE_2 = ContainerImageDate.builder() - .id(IMAGE_DATE_2_ID) - .iid(IMAGE_DATE_2_IMAGE_ID) - .databaseFormat(IMAGE_DATE_2_DATABASE_FORMAT) - .unixFormat(IMAGE_DATE_2_UNIX_FORMAT) - .example(IMAGE_DATE_2_EXAMPLE) - .build(); - - private final static ContainerImageDate IMAGE_DATE_3 = ContainerImageDate.builder() - .id(IMAGE_DATE_3_ID) - .iid(IMAGE_DATE_3_IMAGE_ID) - .databaseFormat(IMAGE_DATE_3_DATABASE_FORMAT) - .unixFormat(IMAGE_DATE_3_UNIX_FORMAT) - .example(IMAGE_DATE_3_EXAMPLE) - .build(); - - private final static ContainerImageDate IMAGE_DATE_4 = ContainerImageDate.builder() - .id(IMAGE_DATE_4_ID) - .iid(IMAGE_DATE_4_IMAGE_ID) - .databaseFormat(IMAGE_DATE_4_DATABASE_FORMAT) - .unixFormat(IMAGE_DATE_4_UNIX_FORMAT) - .example(IMAGE_DATE_4_EXAMPLE) - .build(); - - private final static ContainerImageDate IMAGE_DATE_5 = ContainerImageDate.builder() - .id(IMAGE_DATE_5_ID) - .iid(IMAGE_DATE_5_IMAGE_ID) - .databaseFormat(IMAGE_DATE_5_DATABASE_FORMAT) - .unixFormat(IMAGE_DATE_5_UNIX_FORMAT) - .example(IMAGE_DATE_5_EXAMPLE) - .build(); - - private final static ContainerImage IMAGE_1 = ContainerImage.builder() - .dialect(IMAGE_1_DIALECT) - .driverClass(IMAGE_1_DRIVER) - .jdbcMethod(IMAGE_1_JDBC) - .logo(IMAGE_1_LOGO) - .repository(IMAGE_1_REPOSITORY) - .tag(IMAGE_1_TAG) - .environment(IMAGE_1_ENVIRONMENT) - .defaultPort(IMAGE_1_PORT) - .build(); - - @Autowired - public Seeder(ImageRepository imageRepository, ImageDateRepository imageDateRepository) { - this.imageRepository = imageRepository; - this.imageDateRepository = imageDateRepository; - } - - public void seed() { - if (imageRepository.existsById(IMAGE_1_ID)) { - log.warn("Already seeded. Skip."); - return; - } - final ContainerImage imageMariaDb = imageRepository.save(IMAGE_1); - log.info("Seeded image id {}", imageMariaDb.getId()); - final ContainerImageDate date1 = imageDateRepository.save(IMAGE_DATE_1); - log.info("Seeded image date id {}", date1.getId()); - final ContainerImageDate date2 = imageDateRepository.save(IMAGE_DATE_2); - log.info("Seeded image date id {}", date2.getId()); - final ContainerImageDate date3 = imageDateRepository.save(IMAGE_DATE_3); - log.info("Seeded image date id {}", date3.getId()); - final ContainerImageDate date4 = imageDateRepository.save(IMAGE_DATE_4); - log.info("Seeded image date id {}", date4.getId()); - final ContainerImageDate date5 = imageDateRepository.save(IMAGE_DATE_5); - log.info("Seeded image date id {}", date5.getId()); - } +public interface Seeder { + @EventListener(ApplicationReadyEvent.class) + void seed(); } diff --git a/fda-container-service/services/src/main/java/at/tuwien/seeder/impl/AbstractSeeder.java b/fda-container-service/services/src/main/java/at/tuwien/seeder/impl/AbstractSeeder.java new file mode 100644 index 0000000000000000000000000000000000000000..6c487bebef4120ed7e6cf8f34f1290e2fa35e62c --- /dev/null +++ b/fda-container-service/services/src/main/java/at/tuwien/seeder/impl/AbstractSeeder.java @@ -0,0 +1,148 @@ +package at.tuwien.seeder.impl; + +import at.tuwien.api.container.ContainerCreateRequestDto; +import at.tuwien.entities.container.Container; +import at.tuwien.entities.container.image.ContainerImage; +import at.tuwien.entities.container.image.ContainerImageDate; +import at.tuwien.entities.container.image.ContainerImageEnvironmentItem; +import at.tuwien.entities.container.image.ContainerImageEnvironmentItemType; +import at.tuwien.entities.database.Database; + +import java.util.List; + +public abstract class AbstractSeeder { + + public final static Long IMAGE_1_ID = 1L; + public final static String IMAGE_1_REPOSITORY = "mariadb"; + public final static String IMAGE_1_TAG = "10.5"; + public final static String IMAGE_1_DIALECT = "org.hibernate.dialect.MariaDBDialect"; + public final static String IMAGE_1_DRIVER = "org.mariadb.jdbc.Driver"; + public final static String IMAGE_1_JDBC = "mariadb"; + public final static String IMAGE_1_LOGO = "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"; + public final static Integer IMAGE_1_PORT = 3306; + + public final static List<ContainerImageEnvironmentItem> IMAGE_1_ENVIRONMENT = List.of( + ContainerImageEnvironmentItem.builder() + .iid(IMAGE_1_ID) + .key("ROOT") + .value("root") + .type(ContainerImageEnvironmentItemType.PRIVILEGED_USERNAME) + .build(), + ContainerImageEnvironmentItem.builder() + .iid(IMAGE_1_ID) + .key("MARIADB_ROOT_PASSWORD") + .value("mariadb") + .type(ContainerImageEnvironmentItemType.PRIVILEGED_PASSWORD) + .build(), + ContainerImageEnvironmentItem.builder() + .iid(IMAGE_1_ID) + .key("MARIADB_USER") + .value("mariadb") + .type(ContainerImageEnvironmentItemType.USERNAME) + .build(), + ContainerImageEnvironmentItem.builder() + .iid(IMAGE_1_ID) + .key("MARIADB_PASSWORD") + .value("mariadb") + .type(ContainerImageEnvironmentItemType.PASSWORD) + .build(), + ContainerImageEnvironmentItem.builder() + .iid(IMAGE_1_ID) + .key("TZ") + .value("Europe/Vienna") + .type(ContainerImageEnvironmentItemType.PASSWORD) + .build()); + + public final static Long IMAGE_DATE_1_ID = 1L; + public final static Long IMAGE_DATE_1_IMAGE_ID = IMAGE_1_ID; + public final static String IMAGE_DATE_1_DATABASE_FORMAT = "%Y-%c-%d"; + public final static String IMAGE_DATE_1_UNIX_FORMAT = "yyyy-MM-dd"; + public final static String IMAGE_DATE_1_EXAMPLE = "2022-01-30"; + + public final static Long IMAGE_DATE_2_ID = 2L; + public final static Long IMAGE_DATE_2_IMAGE_ID = IMAGE_1_ID; + public final static String IMAGE_DATE_2_DATABASE_FORMAT = "%d.%c.%Y"; + public final static String IMAGE_DATE_2_UNIX_FORMAT = "yyyy-MM-dd"; + public final static String IMAGE_DATE_2_EXAMPLE = "30.01.2022"; + + public final static Long IMAGE_DATE_3_ID = 3L; + public final static Long IMAGE_DATE_3_IMAGE_ID = IMAGE_1_ID; + public final static String IMAGE_DATE_3_DATABASE_FORMAT = "%d.%c.%y"; + public final static String IMAGE_DATE_3_UNIX_FORMAT = "yyyy-MM-dd"; + public final static String IMAGE_DATE_3_EXAMPLE = "30.01.22"; + + public final static Long IMAGE_DATE_4_ID = 4L; + public final static Long IMAGE_DATE_4_IMAGE_ID = IMAGE_1_ID; + public final static String IMAGE_DATE_4_DATABASE_FORMAT = "%c/%d/%Y"; + public final static String IMAGE_DATE_4_UNIX_FORMAT = "yyyy-MM-dd"; + public final static String IMAGE_DATE_4_EXAMPLE = "01/30/2022"; + + public final static Long IMAGE_DATE_5_ID = 5L; + public final static Long IMAGE_DATE_5_IMAGE_ID = IMAGE_1_ID; + public final static String IMAGE_DATE_5_DATABASE_FORMAT = "%c/%d/%y"; + public final static String IMAGE_DATE_5_UNIX_FORMAT = "yyyy-MM-dd"; + public final static String IMAGE_DATE_5_EXAMPLE = "01/30/22"; + + public final static ContainerImageDate IMAGE_DATE_1 = ContainerImageDate.builder() + .id(IMAGE_DATE_1_ID) + .iid(IMAGE_DATE_1_IMAGE_ID) + .databaseFormat(IMAGE_DATE_1_DATABASE_FORMAT) + .unixFormat(IMAGE_DATE_1_UNIX_FORMAT) + .example(IMAGE_DATE_1_EXAMPLE) + .build(); + + public final static ContainerImageDate IMAGE_DATE_2 = ContainerImageDate.builder() + .id(IMAGE_DATE_2_ID) + .iid(IMAGE_DATE_2_IMAGE_ID) + .databaseFormat(IMAGE_DATE_2_DATABASE_FORMAT) + .unixFormat(IMAGE_DATE_2_UNIX_FORMAT) + .example(IMAGE_DATE_2_EXAMPLE) + .build(); + + public final static ContainerImageDate IMAGE_DATE_3 = ContainerImageDate.builder() + .id(IMAGE_DATE_3_ID) + .iid(IMAGE_DATE_3_IMAGE_ID) + .databaseFormat(IMAGE_DATE_3_DATABASE_FORMAT) + .unixFormat(IMAGE_DATE_3_UNIX_FORMAT) + .example(IMAGE_DATE_3_EXAMPLE) + .build(); + + public final static ContainerImageDate IMAGE_DATE_4 = ContainerImageDate.builder() + .id(IMAGE_DATE_4_ID) + .iid(IMAGE_DATE_4_IMAGE_ID) + .databaseFormat(IMAGE_DATE_4_DATABASE_FORMAT) + .unixFormat(IMAGE_DATE_4_UNIX_FORMAT) + .example(IMAGE_DATE_4_EXAMPLE) + .build(); + + public final static ContainerImageDate IMAGE_DATE_5 = ContainerImageDate.builder() + .id(IMAGE_DATE_5_ID) + .iid(IMAGE_DATE_5_IMAGE_ID) + .databaseFormat(IMAGE_DATE_5_DATABASE_FORMAT) + .unixFormat(IMAGE_DATE_5_UNIX_FORMAT) + .example(IMAGE_DATE_5_EXAMPLE) + .build(); + + public final static ContainerImage IMAGE_1 = ContainerImage.builder() + .dialect(IMAGE_1_DIALECT) + .driverClass(IMAGE_1_DRIVER) + .jdbcMethod(IMAGE_1_JDBC) + .logo(IMAGE_1_LOGO) + .repository(IMAGE_1_REPOSITORY) + .tag(IMAGE_1_TAG) + .environment(IMAGE_1_ENVIRONMENT) + .defaultPort(IMAGE_1_PORT) + .build(); + + public final static Long CONTAINER_1_ID = 1L; + public final static String CONTAINER_1_NAME = "Traffic"; + public final static String CONTAINER_1_REPOSITORY = "mariadb"; + public final static String CONTAINER_1_TAG = "10.5"; + + public final static ContainerCreateRequestDto CONTAINER_1_CREATE_DTO = ContainerCreateRequestDto.builder() + .name(CONTAINER_1_NAME) + .repository(CONTAINER_1_REPOSITORY) + .tag(CONTAINER_1_TAG) + .build(); + +} diff --git a/fda-container-service/services/src/main/java/at/tuwien/seeder/impl/ContainerSeederImpl.java b/fda-container-service/services/src/main/java/at/tuwien/seeder/impl/ContainerSeederImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..c7b5965fee7f589d2c55fd90f905ed2a335f0323 --- /dev/null +++ b/fda-container-service/services/src/main/java/at/tuwien/seeder/impl/ContainerSeederImpl.java @@ -0,0 +1,38 @@ +package at.tuwien.seeder.impl; + +import at.tuwien.entities.container.Container; +import at.tuwien.repository.jpa.ContainerRepository; +import at.tuwien.seeder.Seeder; +import at.tuwien.service.ContainerService; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Slf4j +@Service +public class ContainerSeederImpl extends AbstractSeeder implements Seeder { + + private final ContainerRepository containerRepository; + private final ContainerService containerService; + + @Autowired + public ContainerSeederImpl(ContainerRepository containerRepository, ContainerService containerService) { + this.containerRepository = containerRepository; + this.containerService = containerService; + } + + @SneakyThrows + @Override + public void seed() { + if (containerRepository.existsById(CONTAINER_1_ID)) { + log.warn("Already seeded. Skip."); + return; + } + final Container container1 = containerService.create(CONTAINER_1_CREATE_DTO); + log.info("Created container id {}", container1.getId()); + final Container container1start = containerService.start(CONTAINER_1_ID); + log.info("Started container id {}", container1start.getId()); + } + +} diff --git a/fda-container-service/services/src/main/java/at/tuwien/seeder/impl/ImageSeederImpl.java b/fda-container-service/services/src/main/java/at/tuwien/seeder/impl/ImageSeederImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..373a7489bea7c861c45e9cce420cd5a953160e01 --- /dev/null +++ b/fda-container-service/services/src/main/java/at/tuwien/seeder/impl/ImageSeederImpl.java @@ -0,0 +1,45 @@ +package at.tuwien.seeder.impl; + +import at.tuwien.entities.container.image.ContainerImage; +import at.tuwien.entities.container.image.ContainerImageDate; +import at.tuwien.repository.jpa.ImageDateRepository; +import at.tuwien.repository.jpa.ImageRepository; +import at.tuwien.seeder.Seeder; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Slf4j +@Service +public class ImageSeederImpl extends AbstractSeeder implements Seeder { + + private final ImageRepository imageRepository; + private final ImageDateRepository imageDateRepository; + + @Autowired + public ImageSeederImpl(ImageRepository imageRepository, ImageDateRepository imageDateRepository) { + this.imageRepository = imageRepository; + this.imageDateRepository = imageDateRepository; + } + + @Override + public void seed() { + if (imageRepository.existsById(IMAGE_1_ID)) { + log.warn("Already seeded. Skip."); + return; + } + final ContainerImage imageMariaDb = imageRepository.save(IMAGE_1); + log.info("Seeded image id {}", imageMariaDb.getId()); + final ContainerImageDate date1 = imageDateRepository.save(IMAGE_DATE_1); + log.info("Seeded image date id {}", date1.getId()); + final ContainerImageDate date2 = imageDateRepository.save(IMAGE_DATE_2); + log.info("Seeded image date id {}", date2.getId()); + final ContainerImageDate date3 = imageDateRepository.save(IMAGE_DATE_3); + log.info("Seeded image date id {}", date3.getId()); + final ContainerImageDate date4 = imageDateRepository.save(IMAGE_DATE_4); + log.info("Seeded image date id {}", date4.getId()); + final ContainerImageDate date5 = imageDateRepository.save(IMAGE_DATE_5); + log.info("Seeded image date id {}", date5.getId()); + } + +} diff --git a/fda-container-service/services/src/main/java/at/tuwien/seeder/impl/SeederImpl.java b/fda-container-service/services/src/main/java/at/tuwien/seeder/impl/SeederImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..9869b170fd2df47f128526fcbd9f0cd0e72924b0 --- /dev/null +++ b/fda-container-service/services/src/main/java/at/tuwien/seeder/impl/SeederImpl.java @@ -0,0 +1,35 @@ +package at.tuwien.seeder.impl; + +import at.tuwien.seeder.Seeder; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.context.event.EventListener; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Service; + +import java.util.Arrays; + + +@Slf4j +@Service +public class SeederImpl implements Seeder { + + private final Seeder imageSeederImpl; + private final Environment environment; + private final Seeder containerSeederImpl; + + public SeederImpl(Seeder imageSeederImpl, Environment environment, Seeder containerSeederImpl) { + this.imageSeederImpl = imageSeederImpl; + this.environment = environment; + this.containerSeederImpl = containerSeederImpl; + } + + @Override + @EventListener(ApplicationReadyEvent.class) + public void seed() { + imageSeederImpl.seed(); + if (Arrays.asList(environment.getActiveProfiles()).contains("seeder")) { + containerSeederImpl.seed(); + } + } +} diff --git a/fda-database-service/services/src/main/java/at/tuwien/auth/AuthTokenFilter.java b/fda-database-service/services/src/main/java/at/tuwien/auth/AuthTokenFilter.java index 6bcb362bcd7ed5d338c250782c68145597fce5df..d045b2f82f874b610877615336094ce1b3934bde 100644 --- a/fda-database-service/services/src/main/java/at/tuwien/auth/AuthTokenFilter.java +++ b/fda-database-service/services/src/main/java/at/tuwien/auth/AuthTokenFilter.java @@ -28,7 +28,6 @@ public class AuthTokenFilter extends OncePerRequestFilter { protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String jwt = parseJwt(request); - log.debug("parsed jwt {}", jwt); if (jwt != null) { final UserDetails userDetails = authenticationServiceGateway.validate(jwt); final UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken( @@ -53,4 +52,4 @@ public class AuthTokenFilter extends OncePerRequestFilter { } return null; } -} \ No newline at end of file +} diff --git a/fda-database-service/services/src/main/java/at/tuwien/repository/TableRepository.java b/fda-database-service/services/src/main/java/at/tuwien/repository/jpa/TableRepository.java similarity index 87% rename from fda-database-service/services/src/main/java/at/tuwien/repository/TableRepository.java rename to fda-database-service/services/src/main/java/at/tuwien/repository/jpa/TableRepository.java index a14b277c4f43e72b7a8e283d965efa1efe824ff3..9f01ada5f7e7a2605c6dbaeef7e1b92afce9c05a 100644 --- a/fda-database-service/services/src/main/java/at/tuwien/repository/TableRepository.java +++ b/fda-database-service/services/src/main/java/at/tuwien/repository/jpa/TableRepository.java @@ -1,4 +1,4 @@ -package at.tuwien.repository; +package at.tuwien.repository.jpa; import at.tuwien.entities.database.table.Table; import org.springframework.data.jpa.repository.JpaRepository; diff --git a/fda-database-service/services/src/main/java/at/tuwien/seeder/Seeder.java b/fda-database-service/services/src/main/java/at/tuwien/seeder/Seeder.java new file mode 100644 index 0000000000000000000000000000000000000000..241057caf951d628e2f8935bd4badb27a6a36182 --- /dev/null +++ b/fda-database-service/services/src/main/java/at/tuwien/seeder/Seeder.java @@ -0,0 +1,10 @@ +package at.tuwien.seeder; + +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.context.event.EventListener; + +public interface Seeder { + + @EventListener(ApplicationReadyEvent.class) + void seed(); +} diff --git a/fda-database-service/services/src/main/java/at/tuwien/seeder/impl/AbstractSeeder.java b/fda-database-service/services/src/main/java/at/tuwien/seeder/impl/AbstractSeeder.java new file mode 100644 index 0000000000000000000000000000000000000000..1e6d9a298f2d487bd01b5d5815c733447a7a7d60 --- /dev/null +++ b/fda-database-service/services/src/main/java/at/tuwien/seeder/impl/AbstractSeeder.java @@ -0,0 +1,20 @@ +package at.tuwien.seeder.impl; + +import at.tuwien.api.database.DatabaseCreateDto; + +public abstract class AbstractSeeder { + + public final static Long CONTAINER_1_ID = 1L; + + public final static Long DATABASE_1_ID = 1L; + public final static String DATABASE_1_NAME = "Public Transport in Zürich"; + public final static String DATABASE_1_DESCRIPTION = "Public transport routes and schedules for the city of Zurich https://www.kaggle.com/laa283/zurich-public-transport/version/2"; + public final static Boolean DATABASE_1_PUBLIC = true; + + public final static DatabaseCreateDto DATABASE_1_CREATE_DTO = DatabaseCreateDto.builder() + .name(DATABASE_1_NAME) + .isPublic(DATABASE_1_PUBLIC) + .description(DATABASE_1_DESCRIPTION) + .build(); + +} diff --git a/fda-database-service/services/src/main/java/at/tuwien/seeder/impl/DatabaseSeederImpl.java b/fda-database-service/services/src/main/java/at/tuwien/seeder/impl/DatabaseSeederImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..c0c1c0f8d70ac3a9abdcda177ca6fb351c44cf60 --- /dev/null +++ b/fda-database-service/services/src/main/java/at/tuwien/seeder/impl/DatabaseSeederImpl.java @@ -0,0 +1,36 @@ +package at.tuwien.seeder.impl; + +import at.tuwien.entities.database.Database; +import at.tuwien.repository.jpa.DatabaseRepository; +import at.tuwien.seeder.Seeder; +import at.tuwien.service.DatabaseService; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Slf4j +@Service +public class DatabaseSeederImpl extends AbstractSeeder implements Seeder { + + private final DatabaseService databaseService; + private final DatabaseRepository databaseRepository; + + @Autowired + public DatabaseSeederImpl(DatabaseService databaseService, DatabaseRepository databaseRepository) { + this.databaseService = databaseService; + this.databaseRepository = databaseRepository; + } + + @SneakyThrows + @Override + public void seed() { + if (databaseRepository.existsById(DATABASE_1_ID)) { + log.warn("Already seeded. Skip."); + return; + } + final Database database1 = databaseService.create(CONTAINER_1_ID, DATABASE_1_CREATE_DTO); + log.info("Seeded database id {}", database1.getId()); + } + +} diff --git a/fda-database-service/services/src/main/java/at/tuwien/seeder/impl/SeederImpl.java b/fda-database-service/services/src/main/java/at/tuwien/seeder/impl/SeederImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..3c116262809e6b5295904c4ea500c787612fc9a6 --- /dev/null +++ b/fda-database-service/services/src/main/java/at/tuwien/seeder/impl/SeederImpl.java @@ -0,0 +1,27 @@ +package at.tuwien.seeder.impl; + +import at.tuwien.seeder.Seeder; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.context.annotation.Profile; +import org.springframework.context.event.EventListener; +import org.springframework.stereotype.Service; + + +@Slf4j +@Profile("seeder") +@Service +public class SeederImpl implements Seeder { + + private final Seeder databaseSeederImpl; + + public SeederImpl(Seeder databaseSeederImpl) { + this.databaseSeederImpl = databaseSeederImpl; + } + + @Override + @EventListener(ApplicationReadyEvent.class) + public void seed() { + databaseSeederImpl.seed(); + } +} diff --git a/fda-identifier-service/rest-service/src/main/java/at/tuwien/endpoints/IdentifierEndpoint.java b/fda-identifier-service/rest-service/src/main/java/at/tuwien/endpoints/IdentifierEndpoint.java index 40858946cab00cbe304674128325dd995f0e935e..d41e15dd48980a44c36f406f6d8532c70fedcdf5 100644 --- a/fda-identifier-service/rest-service/src/main/java/at/tuwien/endpoints/IdentifierEndpoint.java +++ b/fda-identifier-service/rest-service/src/main/java/at/tuwien/endpoints/IdentifierEndpoint.java @@ -17,7 +17,6 @@ import org.springframework.web.bind.annotation.*; import javax.validation.Valid; import javax.validation.constraints.NotNull; -import java.security.Principal; import java.util.List; import java.util.stream.Collectors; @@ -46,10 +45,10 @@ public class IdentifierEndpoint { }) public ResponseEntity<List<IdentifierDto>> findAll(@NotNull @PathVariable("id") Long id, @NotNull @PathVariable("databaseId") Long databaseId, - @RequestParam(name = "qid", required = false) Long queryId) + @RequestParam Long qid) throws IdentifierNotFoundException { - if (queryId != null) { - final Identifier identifier = identifierService.find(id, databaseId, queryId); + if (qid != null) { + final Identifier identifier = identifierService.find(id, databaseId, qid); return ResponseEntity.ok(List.of(identifierMapper.identifierToIdentifierDto(identifier))); } final List<Identifier> identifiers = identifierService.findAll(id, databaseId); diff --git a/fda-identifier-service/services/src/main/java/at/tuwien/auth/AuthTokenFilter.java b/fda-identifier-service/services/src/main/java/at/tuwien/auth/AuthTokenFilter.java index 6bcb362bcd7ed5d338c250782c68145597fce5df..d045b2f82f874b610877615336094ce1b3934bde 100644 --- a/fda-identifier-service/services/src/main/java/at/tuwien/auth/AuthTokenFilter.java +++ b/fda-identifier-service/services/src/main/java/at/tuwien/auth/AuthTokenFilter.java @@ -28,7 +28,6 @@ public class AuthTokenFilter extends OncePerRequestFilter { protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String jwt = parseJwt(request); - log.debug("parsed jwt {}", jwt); if (jwt != null) { final UserDetails userDetails = authenticationServiceGateway.validate(jwt); final UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken( @@ -53,4 +52,4 @@ public class AuthTokenFilter extends OncePerRequestFilter { } return null; } -} \ No newline at end of file +} diff --git a/fda-identifier-service/services/src/main/java/at/tuwien/seeder/Seeder.java b/fda-identifier-service/services/src/main/java/at/tuwien/seeder/Seeder.java new file mode 100644 index 0000000000000000000000000000000000000000..241057caf951d628e2f8935bd4badb27a6a36182 --- /dev/null +++ b/fda-identifier-service/services/src/main/java/at/tuwien/seeder/Seeder.java @@ -0,0 +1,10 @@ +package at.tuwien.seeder; + +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.context.event.EventListener; + +public interface Seeder { + + @EventListener(ApplicationReadyEvent.class) + void seed(); +} diff --git a/fda-identifier-service/services/src/main/java/at/tuwien/seeder/impl/AbstractSeeder.java b/fda-identifier-service/services/src/main/java/at/tuwien/seeder/impl/AbstractSeeder.java new file mode 100644 index 0000000000000000000000000000000000000000..0bf27f8a516e6c7e0700829ab076313a581a07cd --- /dev/null +++ b/fda-identifier-service/services/src/main/java/at/tuwien/seeder/impl/AbstractSeeder.java @@ -0,0 +1,31 @@ +package at.tuwien.seeder.impl; + +import at.tuwien.api.identifier.IdentifierDto; +import at.tuwien.api.identifier.VisibilityTypeDto; + +public abstract class AbstractSeeder { + + public final static Long CONTAINER_1_ID = 1L; + + public final static Long DATABASE_1_ID = 1L; + + public final static Long TABLE_1_ID = 1L; + + public final static Long QUERY_1_ID = 1L; + + public final static Long IDENTIFIER_1_ID = 1L; + public final static Long IDENTIFIER_1_QUERY_ID = QUERY_1_ID; + public final static String IDENTIFIER_1_DESCRIPTION = "Query that select the line, date, ride and ride id for 2017"; + public final static String IDENTIFIER_1_TITLE = "Lines with Ride ID"; + public final static VisibilityTypeDto IDENTIFIER_1_VISIBILITY = VisibilityTypeDto.SELF; + + public final static IdentifierDto IDENTIFIER_1_CREATE_DTO = IdentifierDto.builder() + .dbid(DATABASE_1_ID) + .cid(CONTAINER_1_ID) + .description(IDENTIFIER_1_DESCRIPTION) + .title(IDENTIFIER_1_TITLE) + .qid(IDENTIFIER_1_QUERY_ID) + .visibility(IDENTIFIER_1_VISIBILITY) + .build(); + +} diff --git a/fda-identifier-service/services/src/main/java/at/tuwien/seeder/impl/IdentifierSeederImpl.java b/fda-identifier-service/services/src/main/java/at/tuwien/seeder/impl/IdentifierSeederImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..4cf9445bdd86f93a195d18cfff29844d1b1ada46 --- /dev/null +++ b/fda-identifier-service/services/src/main/java/at/tuwien/seeder/impl/IdentifierSeederImpl.java @@ -0,0 +1,36 @@ +package at.tuwien.seeder.impl; + +import at.tuwien.entities.identifier.Identifier; +import at.tuwien.repository.jpa.IdentifierRepository; +import at.tuwien.seeder.Seeder; +import at.tuwien.service.IdentifierService; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Slf4j +@Service +public class IdentifierSeederImpl extends AbstractSeeder implements Seeder { + + private final IdentifierService identifierService; + private final IdentifierRepository identifierRepository; + + @Autowired + public IdentifierSeederImpl(IdentifierService identifierService, IdentifierRepository identifierRepository) { + this.identifierService = identifierService; + this.identifierRepository = identifierRepository; + } + + @SneakyThrows + @Override + public void seed() { + if (identifierRepository.findByQid(QUERY_1_ID).isPresent()) { + log.warn("Already seeded. Skip."); + return; + } + final Identifier identifier1 = identifierService.create(CONTAINER_1_ID, DATABASE_1_ID, IDENTIFIER_1_CREATE_DTO); + log.info("Saved query id {}", identifier1.getId()); + } + +} diff --git a/fda-identifier-service/services/src/main/java/at/tuwien/seeder/impl/SeederImpl.java b/fda-identifier-service/services/src/main/java/at/tuwien/seeder/impl/SeederImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..714c103dbd62ef27a194da12a7794167a0524b55 --- /dev/null +++ b/fda-identifier-service/services/src/main/java/at/tuwien/seeder/impl/SeederImpl.java @@ -0,0 +1,26 @@ +package at.tuwien.seeder.impl; + +import at.tuwien.seeder.Seeder; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.context.annotation.Profile; +import org.springframework.context.event.EventListener; +import org.springframework.stereotype.Service; + +@Slf4j +@Profile("seeder") +@Service +public class SeederImpl implements Seeder { + + private final Seeder databaseSeederImpl; + + public SeederImpl(Seeder databaseSeederImpl) { + this.databaseSeederImpl = databaseSeederImpl; + } + + @Override + @EventListener(ApplicationReadyEvent.class) + public void seed() { + databaseSeederImpl.seed(); + } +} diff --git a/fda-query-service/services/src/main/java/at/tuwien/auth/AuthTokenFilter.java b/fda-query-service/services/src/main/java/at/tuwien/auth/AuthTokenFilter.java index 6bcb362bcd7ed5d338c250782c68145597fce5df..d045b2f82f874b610877615336094ce1b3934bde 100644 --- a/fda-query-service/services/src/main/java/at/tuwien/auth/AuthTokenFilter.java +++ b/fda-query-service/services/src/main/java/at/tuwien/auth/AuthTokenFilter.java @@ -28,7 +28,6 @@ public class AuthTokenFilter extends OncePerRequestFilter { protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String jwt = parseJwt(request); - log.debug("parsed jwt {}", jwt); if (jwt != null) { final UserDetails userDetails = authenticationServiceGateway.validate(jwt); final UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken( @@ -53,4 +52,4 @@ public class AuthTokenFilter extends OncePerRequestFilter { } return null; } -} \ No newline at end of file +} diff --git a/fda-query-service/services/src/main/java/at/tuwien/seeder/Seeder.java b/fda-query-service/services/src/main/java/at/tuwien/seeder/Seeder.java new file mode 100644 index 0000000000000000000000000000000000000000..241057caf951d628e2f8935bd4badb27a6a36182 --- /dev/null +++ b/fda-query-service/services/src/main/java/at/tuwien/seeder/Seeder.java @@ -0,0 +1,10 @@ +package at.tuwien.seeder; + +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.context.event.EventListener; + +public interface Seeder { + + @EventListener(ApplicationReadyEvent.class) + void seed(); +} diff --git a/fda-query-service/services/src/main/java/at/tuwien/seeder/impl/AbstractSeeder.java b/fda-query-service/services/src/main/java/at/tuwien/seeder/impl/AbstractSeeder.java new file mode 100644 index 0000000000000000000000000000000000000000..d8825ef426b0add9b0ae5f6e779a4733126a8219 --- /dev/null +++ b/fda-query-service/services/src/main/java/at/tuwien/seeder/impl/AbstractSeeder.java @@ -0,0 +1,20 @@ +package at.tuwien.seeder.impl; + +import at.tuwien.api.database.query.SaveStatementDto; + +public abstract class AbstractSeeder { + + public final static Long CONTAINER_1_ID = 1L; + + public final static Long DATABASE_1_ID = 1L; + + public final static Long TABLE_1_ID = 1L; + + public final static Long QUERY_1_ID = 1L; + public final static String QUERY_1_STATEMENT = "select `linie`,`betriebsdatum`,`fahrzeug`,`fahrt_id` from `fahrzeiten_soll-ist_2017`"; + + public final static SaveStatementDto QUERY_1_SAVE_DTO = SaveStatementDto.builder() + .statement(QUERY_1_STATEMENT) + .build(); + +} diff --git a/fda-query-service/services/src/main/java/at/tuwien/seeder/impl/QuerySeederImpl.java b/fda-query-service/services/src/main/java/at/tuwien/seeder/impl/QuerySeederImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..98479436783c42a1346781bcd407c4afac98cadd --- /dev/null +++ b/fda-query-service/services/src/main/java/at/tuwien/seeder/impl/QuerySeederImpl.java @@ -0,0 +1,36 @@ +package at.tuwien.seeder.impl; + +import at.tuwien.querystore.Query; +import at.tuwien.seeder.Seeder; +import at.tuwien.service.QueryService; +import at.tuwien.service.StoreService; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Slf4j +@Service +public class QuerySeederImpl extends AbstractSeeder implements Seeder { + + private final StoreService storeService; + private final QueryService queryService; + + @Autowired + public QuerySeederImpl(StoreService storeService, QueryService queryService) { + this.storeService = storeService; + this.queryService = queryService; + } + + @SneakyThrows + @Override + public void seed() { + if (storeService.findAll(CONTAINER_1_ID, DATABASE_1_ID).stream().anyMatch(q -> q.getId().equals(QUERY_1_ID))) { + log.warn("Already seeded. Skip."); + return; + } + final Query query1 = storeService.insert(CONTAINER_1_ID, DATABASE_1_ID, null, QUERY_1_SAVE_DTO); + log.info("Saved query id {}", query1.getId()); + } + +} diff --git a/fda-query-service/services/src/main/java/at/tuwien/seeder/impl/SeederImpl.java b/fda-query-service/services/src/main/java/at/tuwien/seeder/impl/SeederImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..714c103dbd62ef27a194da12a7794167a0524b55 --- /dev/null +++ b/fda-query-service/services/src/main/java/at/tuwien/seeder/impl/SeederImpl.java @@ -0,0 +1,26 @@ +package at.tuwien.seeder.impl; + +import at.tuwien.seeder.Seeder; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.context.annotation.Profile; +import org.springframework.context.event.EventListener; +import org.springframework.stereotype.Service; + +@Slf4j +@Profile("seeder") +@Service +public class SeederImpl implements Seeder { + + private final Seeder databaseSeederImpl; + + public SeederImpl(Seeder databaseSeederImpl) { + this.databaseSeederImpl = databaseSeederImpl; + } + + @Override + @EventListener(ApplicationReadyEvent.class) + public void seed() { + databaseSeederImpl.seed(); + } +} diff --git a/fda-query-service/services/src/main/java/at/tuwien/service/impl/RabbitMqServiceImpl.java b/fda-query-service/services/src/main/java/at/tuwien/service/impl/RabbitMqServiceImpl.java index b1a049dceb81f665cfb7acca2d328d0cbd19109b..3c7c70d65639a63e58f9403f7ae1ed8b40121f26 100644 --- a/fda-query-service/services/src/main/java/at/tuwien/service/impl/RabbitMqServiceImpl.java +++ b/fda-query-service/services/src/main/java/at/tuwien/service/impl/RabbitMqServiceImpl.java @@ -36,6 +36,7 @@ public class RabbitMqServiceImpl implements MessageQueueService { @Transactional public void createUserConsumer(Table table) throws IOException { channel.basicConsume(table.getTopic(), true, (consumerTag, response) -> { + log.debug("received data {}", response); try { queryService.insert(table.getDatabase().getContainer().getId(), table.getDatabase().getId(), table.getId(), @@ -61,7 +62,8 @@ public class RabbitMqServiceImpl implements MessageQueueService { /* ignore */ } }, consumerTag -> {/* */}); - log.debug("declare consumer {}", table); + log.info("Declared consumer for table topic {}", table.getTopic()); + log.info("declared consumer {}", table); } } diff --git a/fda-sensor-computer/main.py b/fda-sensor-computer/main.py index cb7dd167a2ffeffa5ee0da1d228ee9785363d873..c54db1eba5332374e03105acc060e4b325c5c397 100644 --- a/fda-sensor-computer/main.py +++ b/fda-sensor-computer/main.py @@ -1,23 +1,30 @@ #!/usr/bin/env python3 import pika from time import sleep +from sys import argv def get_wifi(): f = open('/sys/class/thermal/thermal_zone0/temp', 'r') - return f.read() + temp = f.read() + return float(temp) / 1000.0 -def send(ex, key, temp): +def send(temp): connection = pika.BlockingConnection() channel = connection.channel() + ex = argv[1] + key = argv[2] channel.basic_publish(exchange=ex, routing_key=key, body=bytes('{"wifi":' + str(temp) + '}', encoding='utf8')) connection.close() if __name__ == "__main__": + if len(argv) != 3: + print("USAGE: ./send EXCHANGE KEY") + exit(1) while 1: t = get_wifi() - send('fda', 'fda.sensors.wifi', t) + send(t) print('sent wifi temperature', t) sleep(1) diff --git a/fda-table-service/rest-service/src/main/java/at/tuwien/endpoints/TableEndpoint.java b/fda-table-service/rest-service/src/main/java/at/tuwien/endpoints/TableEndpoint.java index ba119b721ee95e002685dff7a0c7ea04c5e3727b..b1fd26518847a5947d6304d6c0bb8027da3b3a4d 100644 --- a/fda-table-service/rest-service/src/main/java/at/tuwien/endpoints/TableEndpoint.java +++ b/fda-table-service/rest-service/src/main/java/at/tuwien/endpoints/TableEndpoint.java @@ -76,7 +76,7 @@ public class TableEndpoint { ArbitraryPrimaryKeysException, TableMalformedException, AmqpException, TableNameExistsException, ContainerNotFoundException { final Table table = tableService.createTable(id, databaseId, createDto); - amqpService.createQueue(table); + amqpService.create(table); return ResponseEntity.status(HttpStatus.CREATED) .body(tableMapper.tableToTableBriefDto(table)); } diff --git a/fda-table-service/services/src/main/java/at/tuwien/auth/AuthTokenFilter.java b/fda-table-service/services/src/main/java/at/tuwien/auth/AuthTokenFilter.java index 6bcb362bcd7ed5d338c250782c68145597fce5df..a92f31c071ae273930ee5808cf85c68f39fbe97f 100644 --- a/fda-table-service/services/src/main/java/at/tuwien/auth/AuthTokenFilter.java +++ b/fda-table-service/services/src/main/java/at/tuwien/auth/AuthTokenFilter.java @@ -28,7 +28,6 @@ public class AuthTokenFilter extends OncePerRequestFilter { protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String jwt = parseJwt(request); - log.debug("parsed jwt {}", jwt); if (jwt != null) { final UserDetails userDetails = authenticationServiceGateway.validate(jwt); final UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken( diff --git a/fda-table-service/services/src/main/java/at/tuwien/seeder/Seeder.java b/fda-table-service/services/src/main/java/at/tuwien/seeder/Seeder.java new file mode 100644 index 0000000000000000000000000000000000000000..241057caf951d628e2f8935bd4badb27a6a36182 --- /dev/null +++ b/fda-table-service/services/src/main/java/at/tuwien/seeder/Seeder.java @@ -0,0 +1,10 @@ +package at.tuwien.seeder; + +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.context.event.EventListener; + +public interface Seeder { + + @EventListener(ApplicationReadyEvent.class) + void seed(); +} diff --git a/fda-table-service/services/src/main/java/at/tuwien/seeder/impl/AbstractSeeder.java b/fda-table-service/services/src/main/java/at/tuwien/seeder/impl/AbstractSeeder.java new file mode 100644 index 0000000000000000000000000000000000000000..a296d214fdb651e41c62c06a6a74d0bedd8406db --- /dev/null +++ b/fda-table-service/services/src/main/java/at/tuwien/seeder/impl/AbstractSeeder.java @@ -0,0 +1,370 @@ +package at.tuwien.seeder.impl; + +import at.tuwien.api.database.table.TableCreateDto; +import at.tuwien.api.database.table.columns.ColumnCreateDto; +import at.tuwien.api.database.table.columns.ColumnTypeDto; +import at.tuwien.entities.database.Database; + +public abstract class AbstractSeeder { + + public final static Long CONTAINER_1_ID = 1L; + + public final static Long DATABASE_1_ID = 1L; + + public final static Database DATABASE_1 = Database.builder() + .id(DATABASE_1_ID) + .build(); + + public final static Long TABLE_1_ID = 1L; + public final static String TABLE_1_NAME = "Fahrzeiten Soll-Ist 2017"; + public final static String TABLE_1_FALSE_ELEMENT = null; + public final static String TABLE_1_TRUE_ELEMENT = null; + public final static String TABLE_1_NULL_ELEMENT = null; + public final static Character TABLE_1_SEPERATOR = ','; + public final static String TABLE_1_SKIP_LINES = "1"; + public final static String TABLE_1_DESCRIPTION = "The data table is a variance analysis of the times certain trams and busses should have departed and when they actually departed."; + + public final static Long IMAGE_DATE_3_ID = 3L; + + public final static TableCreateDto TABLE_1_CREATE_DTO = TableCreateDto.builder() + .name(TABLE_1_NAME) + .description(TABLE_1_DESCRIPTION) + .falseElement(TABLE_1_FALSE_ELEMENT) + .trueElement(TABLE_1_TRUE_ELEMENT) + .nullElement(TABLE_1_NULL_ELEMENT) + .separator(TABLE_1_SEPERATOR) + .skipLines(TABLE_1_SKIP_LINES) + .columns(new ColumnCreateDto[]{ + ColumnCreateDto.builder() + .type(ColumnTypeDto.NUMBER) + .name("linie") + .nullAllowed(true) + .primaryKey(false) + .unique(false) + .dfid(null) + .checkExpression(null) + .enumValues(null) + .build(), + ColumnCreateDto.builder() + .type(ColumnTypeDto.NUMBER) + .name("richtung") + .nullAllowed(true) + .primaryKey(false) + .unique(false) + .dfid(null) + .checkExpression(null) + .enumValues(null) + .build(), + ColumnCreateDto.builder() + .type(ColumnTypeDto.DATE) + .name("betriebsdatum") + .nullAllowed(true) + .primaryKey(false) + .unique(false) + .dfid(IMAGE_DATE_3_ID) + .checkExpression(null) + .enumValues(null) + .build(), + ColumnCreateDto.builder() + .type(ColumnTypeDto.NUMBER) + .name("fahrzeug") + .nullAllowed(true) + .primaryKey(false) + .unique(false) + .dfid(null) + .checkExpression(null) + .enumValues(null) + .build(), + ColumnCreateDto.builder() + .type(ColumnTypeDto.NUMBER) + .name("kurs") + .nullAllowed(true) + .primaryKey(false) + .unique(false) + .dfid(null) + .checkExpression(null) + .enumValues(null) + .build(), + ColumnCreateDto.builder() + .type(ColumnTypeDto.NUMBER) + .name("seq_von") + .nullAllowed(true) + .primaryKey(false) + .unique(false) + .dfid(null) + .checkExpression(null) + .enumValues(null) + .build(), + ColumnCreateDto.builder() + .type(ColumnTypeDto.NUMBER) + .name("halt_diva_von") + .nullAllowed(true) + .primaryKey(false) + .unique(false) + .dfid(null) + .checkExpression(null) + .enumValues(null) + .build(), + ColumnCreateDto.builder() + .type(ColumnTypeDto.NUMBER) + .name("halt_punkt_diva_von") + .nullAllowed(true) + .primaryKey(false) + .unique(false) + .dfid(null) + .checkExpression(null) + .enumValues(null) + .build(), + ColumnCreateDto.builder() + .type(ColumnTypeDto.NUMBER) + .name("halt_kurz_von1") + .nullAllowed(true) + .primaryKey(false) + .unique(false) + .dfid(null) + .checkExpression(null) + .enumValues(null) + .build(), + ColumnCreateDto.builder() + .type(ColumnTypeDto.DATE) + .name("datum_von") + .nullAllowed(true) + .primaryKey(false) + .unique(false) + .dfid(IMAGE_DATE_3_ID) + .checkExpression(null) + .enumValues(null) + .build(), + ColumnCreateDto.builder() + .type(ColumnTypeDto.NUMBER) + .name("soll_an_von") + .nullAllowed(true) + .primaryKey(false) + .unique(false) + .dfid(null) + .checkExpression(null) + .enumValues(null) + .build(), + ColumnCreateDto.builder() + .type(ColumnTypeDto.NUMBER) + .name("ist_an_von") + .nullAllowed(true) + .primaryKey(false) + .unique(false) + .dfid(null) + .checkExpression(null) + .enumValues(null) + .build(), + ColumnCreateDto.builder() + .type(ColumnTypeDto.NUMBER) + .name("soll_ab_von") + .nullAllowed(true) + .primaryKey(false) + .unique(false) + .dfid(null) + .checkExpression(null) + .enumValues(null) + .build(), + ColumnCreateDto.builder() + .type(ColumnTypeDto.NUMBER) + .name("seq_nach") + .nullAllowed(true) + .primaryKey(false) + .unique(false) + .dfid(null) + .checkExpression(null) + .enumValues(null) + .build(), + ColumnCreateDto.builder() + .type(ColumnTypeDto.NUMBER) + .name("halt_diva_nach") + .nullAllowed(true) + .primaryKey(false) + .unique(false) + .dfid(null) + .checkExpression(null) + .enumValues(null) + .build(), + ColumnCreateDto.builder() + .type(ColumnTypeDto.NUMBER) + .name("halt_punkt_diva_nach") + .nullAllowed(true) + .primaryKey(false) + .unique(false) + .dfid(null) + .checkExpression(null) + .enumValues(null) + .build(), + ColumnCreateDto.builder() + .type(ColumnTypeDto.NUMBER) + .name("halt_kurz_nach1") + .nullAllowed(true) + .primaryKey(false) + .unique(false) + .dfid(null) + .checkExpression(null) + .enumValues(null) + .build(), + ColumnCreateDto.builder() + .type(ColumnTypeDto.DATE) + .name("datum_nach") + .nullAllowed(true) + .primaryKey(false) + .unique(false) + .dfid(IMAGE_DATE_3_ID) + .checkExpression(null) + .enumValues(null) + .build(), + ColumnCreateDto.builder() + .type(ColumnTypeDto.NUMBER) + .name("soll_an_nach") + .nullAllowed(true) + .primaryKey(false) + .unique(false) + .dfid(null) + .checkExpression(null) + .enumValues(null) + .build(), + ColumnCreateDto.builder() + .type(ColumnTypeDto.NUMBER) + .name("ist_an_nach1") + .nullAllowed(true) + .primaryKey(false) + .unique(false) + .dfid(null) + .checkExpression(null) + .enumValues(null) + .build(), + ColumnCreateDto.builder() + .type(ColumnTypeDto.NUMBER) + .name("soll_ab_nach") + .nullAllowed(true) + .primaryKey(false) + .unique(false) + .dfid(null) + .checkExpression(null) + .enumValues(null) + .build(), + ColumnCreateDto.builder() + .type(ColumnTypeDto.NUMBER) + .name("ist_ab_nach") + .nullAllowed(true) + .primaryKey(false) + .unique(false) + .dfid(null) + .checkExpression(null) + .enumValues(null) + .build(), + ColumnCreateDto.builder() + .type(ColumnTypeDto.NUMBER) + .name("fahrt_id") + .nullAllowed(true) + .primaryKey(false) + .unique(false) + .dfid(null) + .checkExpression(null) + .enumValues(null) + .build(), + ColumnCreateDto.builder() + .type(ColumnTypeDto.NUMBER) + .name("fahrweg_id") + .nullAllowed(true) + .primaryKey(false) + .unique(false) + .dfid(null) + .checkExpression(null) + .enumValues(null) + .build(), + ColumnCreateDto.builder() + .type(ColumnTypeDto.NUMBER) + .name("fw_no") + .nullAllowed(true) + .primaryKey(false) + .unique(false) + .dfid(null) + .checkExpression(null) + .enumValues(null) + .build(), + ColumnCreateDto.builder() + .type(ColumnTypeDto.NUMBER) + .name("fw_typ") + .nullAllowed(true) + .primaryKey(false) + .unique(false) + .dfid(null) + .checkExpression(null) + .enumValues(null) + .build(), + ColumnCreateDto.builder() + .type(ColumnTypeDto.NUMBER) + .name("fw_kurz") + .nullAllowed(true) + .primaryKey(false) + .unique(false) + .dfid(null) + .checkExpression(null) + .enumValues(null) + .build(), + ColumnCreateDto.builder() + .type(ColumnTypeDto.STRING) + .name("fw_lang") + .nullAllowed(true) + .primaryKey(false) + .unique(false) + .dfid(null) + .checkExpression(null) + .enumValues(null) + .build(), + ColumnCreateDto.builder() + .type(ColumnTypeDto.NUMBER) + .name("umlauf_von") + .nullAllowed(true) + .primaryKey(false) + .unique(false) + .dfid(null) + .checkExpression(null) + .enumValues(null) + .build(), + ColumnCreateDto.builder() + .type(ColumnTypeDto.NUMBER) + .name("halt_id_von") + .nullAllowed(true) + .primaryKey(false) + .unique(false) + .dfid(null) + .checkExpression(null) + .enumValues(null) + .build(), + ColumnCreateDto.builder() + .type(ColumnTypeDto.NUMBER) + .name("halt_id_nach") + .nullAllowed(true) + .primaryKey(false) + .unique(false) + .dfid(null) + .checkExpression(null) + .enumValues(null) + .build(), + ColumnCreateDto.builder() + .type(ColumnTypeDto.NUMBER) + .name("halt_punkt_id_von") + .nullAllowed(true) + .primaryKey(false) + .unique(false) + .dfid(null) + .checkExpression(null) + .enumValues(null) + .build(), + ColumnCreateDto.builder() + .type(ColumnTypeDto.NUMBER) + .name("halt_punkt_id_nach") + .nullAllowed(true) + .primaryKey(false) + .unique(false) + .dfid(null) + .checkExpression(null) + .enumValues(null) + .build()}) + .build(); + +} diff --git a/fda-table-service/services/src/main/java/at/tuwien/seeder/impl/SeederImpl.java b/fda-table-service/services/src/main/java/at/tuwien/seeder/impl/SeederImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..3c116262809e6b5295904c4ea500c787612fc9a6 --- /dev/null +++ b/fda-table-service/services/src/main/java/at/tuwien/seeder/impl/SeederImpl.java @@ -0,0 +1,27 @@ +package at.tuwien.seeder.impl; + +import at.tuwien.seeder.Seeder; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.context.annotation.Profile; +import org.springframework.context.event.EventListener; +import org.springframework.stereotype.Service; + + +@Slf4j +@Profile("seeder") +@Service +public class SeederImpl implements Seeder { + + private final Seeder databaseSeederImpl; + + public SeederImpl(Seeder databaseSeederImpl) { + this.databaseSeederImpl = databaseSeederImpl; + } + + @Override + @EventListener(ApplicationReadyEvent.class) + public void seed() { + databaseSeederImpl.seed(); + } +} diff --git a/fda-table-service/services/src/main/java/at/tuwien/seeder/impl/TableSeederImpl.java b/fda-table-service/services/src/main/java/at/tuwien/seeder/impl/TableSeederImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..cdaadbed91bb6aa62efd2056e52939ac780a3634 --- /dev/null +++ b/fda-table-service/services/src/main/java/at/tuwien/seeder/impl/TableSeederImpl.java @@ -0,0 +1,36 @@ +package at.tuwien.seeder.impl; + +import at.tuwien.entities.database.table.Table; +import at.tuwien.repository.jpa.TableRepository; +import at.tuwien.seeder.Seeder; +import at.tuwien.service.TableService; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Slf4j +@Service +public class TableSeederImpl extends AbstractSeeder implements Seeder { + + private final TableService tableService; + private final TableRepository tableRepository; + + @Autowired + public TableSeederImpl(TableService tableService, TableRepository tableRepository) { + this.tableService = tableService; + this.tableRepository = tableRepository; + } + + @SneakyThrows + @Override + public void seed() { + if (tableRepository.findByDatabaseAndId(DATABASE_1, TABLE_1_ID).isPresent()) { + log.warn("Already seeded. Skip."); + return; + } + final Table table1 = tableService.createTable(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_CREATE_DTO); + log.info("Seeded table id {}", table1.getId()); + } + +} diff --git a/fda-table-service/services/src/main/java/at/tuwien/service/MessageQueueService.java b/fda-table-service/services/src/main/java/at/tuwien/service/MessageQueueService.java index dd8e9e46e6648f1b55a48c0b28c442b620586110..549d9b3602fd7ecfb01143be4a23779b99b29235 100644 --- a/fda-table-service/services/src/main/java/at/tuwien/service/MessageQueueService.java +++ b/fda-table-service/services/src/main/java/at/tuwien/service/MessageQueueService.java @@ -1,6 +1,5 @@ package at.tuwien.service; -import at.tuwien.entities.database.Database; import at.tuwien.entities.database.table.Table; import at.tuwien.exception.AmqpException; @@ -13,29 +12,13 @@ public interface MessageQueueService { * * @throws IOException Error on any of these actions. */ - void init() throws IOException; - - /** - * Creates a queue/topic for a table. - * - * @param table The table. - * @throws AmqpException Creation failed. - */ - void createQueue(Table table) throws AmqpException; - - /** - * Creates an exchange for a database. - * - * @param database The database. - * @throws IOException Creation failed. - */ - void create(Database database) throws IOException; + void init() throws IOException, AmqpException; /** * Creates a queue for a table. * * @param table The table. - * @throws IOException Creation failed. + * @throws AmqpException Creation failed. */ - void create(Table table) throws IOException; + void create(Table table) throws AmqpException; } diff --git a/fda-table-service/services/src/main/java/at/tuwien/service/impl/RabbitMqService.java b/fda-table-service/services/src/main/java/at/tuwien/service/impl/RabbitMqService.java index c0d15adccf2ef08c7a2935fac459377e97cf6cb0..5f44df62609bd685a282b2aa9d8445099da0d48e 100644 --- a/fda-table-service/services/src/main/java/at/tuwien/service/impl/RabbitMqService.java +++ b/fda-table-service/services/src/main/java/at/tuwien/service/impl/RabbitMqService.java @@ -1,8 +1,7 @@ package at.tuwien.service.impl; -import at.tuwien.entities.database.Database; import at.tuwien.entities.database.table.Table; -import at.tuwien.exception.*; +import at.tuwien.exception.AmqpException; import at.tuwien.repository.jpa.TableRepository; import at.tuwien.service.MessageQueueService; import com.rabbitmq.client.BuiltinExchangeType; @@ -40,7 +39,7 @@ public class RabbitMqService implements MessageQueueService { @Override @EventListener(ApplicationReadyEvent.class) @Transactional - public void init() throws IOException { + public void init() throws IOException, AmqpException { channel.exchangeDeclare(AMQP_EXCHANGE, BuiltinExchangeType.TOPIC, true); final List<Table> tables = tableRepository.findAll(); for (Table table : tables) { @@ -49,32 +48,16 @@ public class RabbitMqService implements MessageQueueService { } @Override - public void createQueue(Table table) throws AmqpException { + @Transactional + public void create(Table table) throws AmqpException { try { - create(table); - log.info("Created queue for table with id {}", table.getId()); - log.debug("created queue and consumer for table {}", table); + channel.queueDeclare(table.getTopic(), true, false, false, null); + channel.queueBind(table.getTopic(), table.getDatabase().getExchange(), table.getTopic()); } catch (IOException e) { - log.error("Could not create exchange and consumer: {}", e.getMessage()); - throw new AmqpException("Could not create exchange and consumer", e); + log.error("Failed to create queue and bind for table with id {}", table.getId()); + log.debug("Failed to create queue and bind for table {}", table); + throw new AmqpException("Failed to create", e); } - } - - @Override - @Transactional - public void create(Database database) throws IOException { - channel.exchangeDeclare(database.getExchange(), BuiltinExchangeType.FANOUT, true); - channel.exchangeBind(database.getExchange(), AMQP_EXCHANGE, database.getExchange()); - log.info("Created exchange for database with id {}", database.getId()); - log.debug("declare fanout exchange {}", database.getExchange()); - log.debug("bind exchange {} to {}", database.getExchange(), AMQP_EXCHANGE); - } - - @Override - @Transactional - public void create(Table table) throws IOException { - channel.queueDeclare(table.getTopic(), true, false, false, null); - channel.queueBind(table.getTopic(), table.getDatabase().getExchange(), table.getTopic()); log.info("Created queue for database with id {}", table.getId()); log.debug("declare queue for table {}", table); log.debug("bind queue to {}", table.getDatabase().getExchange()); diff --git a/fda-ui/pages/pid/_pid_id/index.vue b/fda-ui/pages/pid/_pid_id/index.vue index 24c62a04fa4f66ea7a6a954951cb2048a424d8f3..da067561823f2af862cfc9eadaf631271e73b930 100644 --- a/fda-ui/pages/pid/_pid_id/index.vue +++ b/fda-ui/pages/pid/_pid_id/index.vue @@ -1,6 +1,6 @@ <template> <div> - <v-card> + <v-card v-if="loading"> <v-card-title>PID Not Found</v-card-title> <v-card-subtitle>{{ pid }}</v-card-subtitle> <v-card-text> @@ -17,16 +17,22 @@ <script> export default { - mounted () { - this.findPid() + data () { + return { + loading: false + } }, computed: { pid () { return this.$route.params.pid_id } }, + mounted () { + this.findPid() + }, methods: { async findPid () { + this.loading = true try { const res = await this.$axios.get(`/api/pid/${this.$route.params.pid_id}`) console.debug('persistent id', res.data) @@ -34,8 +40,8 @@ export default { } catch (err) { console.error('Could not load query', err) this.$toast.error('Could not load query') - this.loading = false } + this.loading = false } } }