From 040dc21027b83ee08242aa73fc938f6498eb1a19 Mon Sep 17 00:00:00 2001 From: MDeLuise <66636702+MDeLuise@users.noreply.github.com> Date: Fri, 19 May 2023 16:55:55 +0200 Subject: [PATCH] Hello Project! --- .github/ISSUE_TEMPLATE/bug_report.yml | 40 + .github/ISSUE_TEMPLATE/fr.yml | 38 + .github/ISSUE_TEMPLATE/question.yml | 9 + .github/pull_request_template.md | 15 + .github/workflows/main.yml | 40 + .gitignore | 1 + README.md | 135 + backend/.gitignore | 10 + backend/deployment/Dockerfile | 6 + backend/images/swagger.png | Bin 0 -> 941611 bytes backend/mvnw | 316 + backend/mvnw.cmd | 188 + backend/pom.xml | 176 + .../github/mdeluise/plantit/Application.java | 12 + .../mdeluise/plantit/ApplicationConfig.java | 70 + .../authentication/AuthController.java | 96 + .../mdeluise/plantit/authentication/User.java | 168 + .../authentication/UserController.java | 72 + .../authentication/UserRepository.java | 14 + .../plantit/authentication/UserService.java | 82 + .../payload/request/LoginRequest.java | 10 + .../payload/request/SignupRequest.java | 13 + .../payload/response/MessageResponse.java | 20 + .../payload/response/UserInfoResponse.java | 6 + .../plantit/botanicalinfo/BotanicalInfo.java | 133 + .../BotanicalInfoController.java | 69 + .../botanicalinfo/BotanicalInfoDTO.java | 94 + .../BotanicalInfoDTOConverter.java | 30 + .../BotanicalInfoRepository.java | 14 + .../botanicalinfo/BotanicalInfoService.java | 85 + .../botanicalinfo/GlobalBotanicalInfo.java | 9 + .../UserCreatedBotanicalInfo.java | 25 + .../plantit/common/AbstractDTOConverter.java | 17 + .../common/AuthenticatedUserService.java | 28 + .../github/mdeluise/plantit/diary/Diary.java | 77 + .../plantit/diary/DiaryController.java | 108 + .../mdeluise/plantit/diary/DiaryDTO.java | 55 + .../plantit/diary/DiaryDTOConverter.java | 28 + .../plantit/diary/DiaryRepository.java | 15 + .../mdeluise/plantit/diary/DiaryService.java | 39 + .../plantit/diary/entry/DiaryEntry.java | 82 + .../plantit/diary/entry/DiaryEntryDTO.java | 93 + .../diary/entry/DiaryEntryDTOConverter.java | 30 + .../diary/entry/DiaryEntryRepository.java | 15 + .../diary/entry/DiaryEntryService.java | 95 + .../plantit/diary/entry/DiaryEntryType.java | 13 + .../exception/ControllerExceptionHandler.java | 42 + .../plantit/exception/ErrorMessage.java | 6 + .../exception/InfoExtractionException.java | 12 + ...MaximumNumberOfUsersReachedExceptions.java | 7 + .../exception/ResourceNotFoundException.java | 29 + .../plantit/image/BotanicalInfoImage.java | 31 + .../mdeluise/plantit/image/EntityImage.java | 15 + .../plantit/image/EntityImageImpl.java | 97 + .../plantit/image/ImageController.java | 97 + .../mdeluise/plantit/image/ImageDTO.java | 69 + .../plantit/image/ImageDTOConverter.java | 26 + .../plantit/image/ImageRepository.java | 6 + .../mdeluise/plantit/image/ImageTarget.java | 5 + .../mdeluise/plantit/image/ImageUtility.java | 46 + .../mdeluise/plantit/image/PlantImage.java | 30 + .../plantit/image/PlantImageRepository.java | 18 + .../FileSystemImageStorageService.java | 161 + .../image/storage/ImageStorageService.java | 25 + .../image/storage/StorageException.java | 12 + .../storage/StorageFileNotFoundException.java | 12 + .../image/storage/StorageProperties.java | 18 + .../github/mdeluise/plantit/plant/Plant.java | 168 + .../plantit/plant/PlantController.java | 69 + .../mdeluise/plantit/plant/PlantDTO.java | 157 + .../plantit/plant/PlantDTOConverter.java | 35 + .../plantit/plant/PlantRepository.java | 14 + .../mdeluise/plantit/plant/PlantService.java | 96 + .../mdeluise/plantit/plant/PlantState.java | 9 + .../plantinfo/AbstractPlantInfoExtractor.java | 69 + .../plantinfo/PlantInfoExtractorFactory.java | 28 + .../local/LocalPlantInfoExtractor.java | 35 + .../trafle/TreflePlantInfoExtractor.java | 40 + .../plantinfo/trafle/TrefleRequestMaker.java | 128 + .../security/ApplicationSecurityConfig.java | 116 + .../plantit/security/apikey/ApiKey.java | 88 + .../security/apikey/ApiKeyController.java | 105 + .../plantit/security/apikey/ApiKeyDTO.java | 59 + .../security/apikey/ApiKeyDTOConverter.java | 30 + .../plantit/security/apikey/ApiKeyFilter.java | 87 + .../security/apikey/ApiKeyRepository.java | 20 + .../security/apikey/ApiKeyService.java | 85 + .../plantit/security/jwt/JwtTokenFilter.java | 94 + .../plantit/security/jwt/JwtTokenInfo.java | 15 + .../plantit/security/jwt/JwtTokenUtil.java | 62 + .../plantit/security/jwt/JwtWebUtil.java | 49 + .../security/services/UserDetailsImpl.java | 107 + .../services/UserDetailsServiceImpl.java | 32 + .../systeminfo/SystemInfoController.java | 41 + .../main/resources/application-dev.properties | 95 + .../application-integration.properties | 74 + .../src/main/resources/application.properties | 76 + backend/src/main/resources/checkstyle.xml | 290 + .../dblogs/changelog/changelog-master-dev.xml | 10 + .../changelog-master-integration.xml | 8 + .../dblogs/changelog/changelog-master.xml | 8 + .../dblogs/changelog/changes/changelog-0.xml | 212 + .../dblogs/changelog/init-dummy-data.xml | 164 + .../resources/dblogs/changelog/init-users.xml | 38 + .../main/resources/upload-dir/dummy-image.jpg | Bin 0 -> 388131 bytes .../mdeluise/plantit/ApplicationTest.java | 15 + .../mdeluise/plantit/TestEnvironment.java | 28 + .../CucumberSpringContextConfiguration.java | 16 + .../integration/IntegrationRunnerTest.java | 17 + .../steps/AuthenticationSteps.java | 45 + .../integration/steps/IntegrationSteps.java | 205 + .../plantit/integration/steps/StepData.java | 60 + .../resources/features/authentication.feature | 40 + .../resources/features/integration.feature | 29 + deployment/Jenkinsfile | 198 + deployment/backend.env | 12 + deployment/default.conf | 51 + deployment/docker-compose.yml | 36 + deployment/frontend.env | 3 + frontend/.dockerignore | 31 + frontend/.env | 2 + frontend/.gitignore | 27 + frontend/README.md | 46 + frontend/deployment/Dockerfile | 18 + frontend/deployment/conf/conf.d/default.conf | 13 + frontend/deployment/conf/conf.d/gzip.conf | 24 + frontend/env.sh | 34 + frontend/package-lock.json | 18005 ++++++++++++++++ frontend/package.json | 74 + frontend/public/botanical-info-no-img.png | Bin 0 -> 2840 bytes frontend/public/favicon.ico | Bin 0 -> 3870 bytes frontend/public/index.html | 50 + frontend/public/logo192.png | Bin 0 -> 5347 bytes frontend/public/logo512.png | Bin 0 -> 9664 bytes frontend/public/manifest.json | 25 + frontend/public/robots.txt | 3 + frontend/src/App.css | 39 + frontend/src/App.test.tsx | 10 + frontend/src/App.tsx | 114 + frontend/src/common.ts | 32 + frontend/src/components/AddLogEntry.tsx | 248 + frontend/src/components/AddPlant.tsx | 329 + frontend/src/components/AllLogs.tsx | 252 + frontend/src/components/Auth.tsx | 159 + frontend/src/components/BottomBar.tsx | 138 + frontend/src/components/EditEvent.tsx | 310 + frontend/src/components/Home.tsx | 323 + frontend/src/components/LogEntry.tsx | 76 + frontend/src/components/PlantDetails.tsx | 403 + frontend/src/components/SearchPage.tsx | 252 + frontend/src/components/Settings.tsx | 175 + frontend/src/components/UserPlant.tsx | 67 + frontend/src/index.css | 13 + frontend/src/index.tsx | 29 + frontend/src/interfaces.ts | 32 + frontend/src/logo.svg | 1 + frontend/src/react-app-env.d.ts | 1 + frontend/src/reportWebVitals.ts | 15 + frontend/src/setupTests.ts | 5 + frontend/src/style/BottomBar.scss | 13 + frontend/tsconfig.json | 27 + images/plant-it-logo.png | Bin 0 -> 271598 bytes images/screenshot-1.png | Bin 0 -> 1293053 bytes images/screenshot-2.png | Bin 0 -> 865565 bytes images/screenshot-3.png | Bin 0 -> 1883901 bytes images/screenshot-4.png | Bin 0 -> 773962 bytes package-lock.json | 6 + 167 files changed, 28444 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.yml create mode 100644 .github/ISSUE_TEMPLATE/fr.yml create mode 100644 .github/ISSUE_TEMPLATE/question.yml create mode 100644 .github/pull_request_template.md create mode 100644 .github/workflows/main.yml create mode 100644 .gitignore create mode 100644 README.md create mode 100644 backend/.gitignore create mode 100644 backend/deployment/Dockerfile create mode 100644 backend/images/swagger.png create mode 100755 backend/mvnw create mode 100644 backend/mvnw.cmd create mode 100644 backend/pom.xml create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/Application.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/ApplicationConfig.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/authentication/AuthController.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/authentication/User.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/authentication/UserController.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/authentication/UserRepository.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/authentication/UserService.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/authentication/payload/request/LoginRequest.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/authentication/payload/request/SignupRequest.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/authentication/payload/response/MessageResponse.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/authentication/payload/response/UserInfoResponse.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/botanicalinfo/BotanicalInfo.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/botanicalinfo/BotanicalInfoController.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/botanicalinfo/BotanicalInfoDTO.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/botanicalinfo/BotanicalInfoDTOConverter.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/botanicalinfo/BotanicalInfoRepository.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/botanicalinfo/BotanicalInfoService.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/botanicalinfo/GlobalBotanicalInfo.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/botanicalinfo/UserCreatedBotanicalInfo.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/common/AbstractDTOConverter.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/common/AuthenticatedUserService.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/diary/Diary.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/diary/DiaryController.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/diary/DiaryDTO.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/diary/DiaryDTOConverter.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/diary/DiaryRepository.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/diary/DiaryService.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/diary/entry/DiaryEntry.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/diary/entry/DiaryEntryDTO.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/diary/entry/DiaryEntryDTOConverter.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/diary/entry/DiaryEntryRepository.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/diary/entry/DiaryEntryService.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/diary/entry/DiaryEntryType.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/exception/ControllerExceptionHandler.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/exception/ErrorMessage.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/exception/InfoExtractionException.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/exception/MaximumNumberOfUsersReachedExceptions.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/exception/ResourceNotFoundException.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/image/BotanicalInfoImage.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/image/EntityImage.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/image/EntityImageImpl.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/image/ImageController.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/image/ImageDTO.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/image/ImageDTOConverter.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/image/ImageRepository.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/image/ImageTarget.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/image/ImageUtility.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/image/PlantImage.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/image/PlantImageRepository.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/image/storage/FileSystemImageStorageService.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/image/storage/ImageStorageService.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/image/storage/StorageException.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/image/storage/StorageFileNotFoundException.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/image/storage/StorageProperties.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/plant/Plant.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/plant/PlantController.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/plant/PlantDTO.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/plant/PlantDTOConverter.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/plant/PlantRepository.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/plant/PlantService.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/plant/PlantState.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/plantinfo/AbstractPlantInfoExtractor.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/plantinfo/PlantInfoExtractorFactory.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/plantinfo/local/LocalPlantInfoExtractor.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/plantinfo/trafle/TreflePlantInfoExtractor.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/plantinfo/trafle/TrefleRequestMaker.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/security/ApplicationSecurityConfig.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/security/apikey/ApiKey.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/security/apikey/ApiKeyController.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/security/apikey/ApiKeyDTO.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/security/apikey/ApiKeyDTOConverter.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/security/apikey/ApiKeyFilter.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/security/apikey/ApiKeyRepository.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/security/apikey/ApiKeyService.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/security/jwt/JwtTokenFilter.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/security/jwt/JwtTokenInfo.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/security/jwt/JwtTokenUtil.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/security/jwt/JwtWebUtil.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/security/services/UserDetailsImpl.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/security/services/UserDetailsServiceImpl.java create mode 100644 backend/src/main/java/com/github/mdeluise/plantit/systeminfo/SystemInfoController.java create mode 100644 backend/src/main/resources/application-dev.properties create mode 100644 backend/src/main/resources/application-integration.properties create mode 100644 backend/src/main/resources/application.properties create mode 100644 backend/src/main/resources/checkstyle.xml create mode 100644 backend/src/main/resources/dblogs/changelog/changelog-master-dev.xml create mode 100644 backend/src/main/resources/dblogs/changelog/changelog-master-integration.xml create mode 100644 backend/src/main/resources/dblogs/changelog/changelog-master.xml create mode 100644 backend/src/main/resources/dblogs/changelog/changes/changelog-0.xml create mode 100644 backend/src/main/resources/dblogs/changelog/init-dummy-data.xml create mode 100644 backend/src/main/resources/dblogs/changelog/init-users.xml create mode 100644 backend/src/main/resources/upload-dir/dummy-image.jpg create mode 100644 backend/src/test/java/com/github/mdeluise/plantit/ApplicationTest.java create mode 100644 backend/src/test/java/com/github/mdeluise/plantit/TestEnvironment.java create mode 100644 backend/src/test/java/com/github/mdeluise/plantit/integration/CucumberSpringContextConfiguration.java create mode 100644 backend/src/test/java/com/github/mdeluise/plantit/integration/IntegrationRunnerTest.java create mode 100644 backend/src/test/java/com/github/mdeluise/plantit/integration/steps/AuthenticationSteps.java create mode 100644 backend/src/test/java/com/github/mdeluise/plantit/integration/steps/IntegrationSteps.java create mode 100644 backend/src/test/java/com/github/mdeluise/plantit/integration/steps/StepData.java create mode 100644 backend/src/test/resources/features/authentication.feature create mode 100644 backend/src/test/resources/features/integration.feature create mode 100644 deployment/Jenkinsfile create mode 100644 deployment/backend.env create mode 100644 deployment/default.conf create mode 100644 deployment/docker-compose.yml create mode 100644 deployment/frontend.env create mode 100644 frontend/.dockerignore create mode 100644 frontend/.env create mode 100644 frontend/.gitignore create mode 100644 frontend/README.md create mode 100644 frontend/deployment/Dockerfile create mode 100644 frontend/deployment/conf/conf.d/default.conf create mode 100644 frontend/deployment/conf/conf.d/gzip.conf create mode 100755 frontend/env.sh create mode 100644 frontend/package-lock.json create mode 100644 frontend/package.json create mode 100644 frontend/public/botanical-info-no-img.png create mode 100644 frontend/public/favicon.ico create mode 100644 frontend/public/index.html create mode 100644 frontend/public/logo192.png create mode 100644 frontend/public/logo512.png create mode 100644 frontend/public/manifest.json create mode 100644 frontend/public/robots.txt create mode 100644 frontend/src/App.css create mode 100644 frontend/src/App.test.tsx create mode 100644 frontend/src/App.tsx create mode 100644 frontend/src/common.ts create mode 100644 frontend/src/components/AddLogEntry.tsx create mode 100644 frontend/src/components/AddPlant.tsx create mode 100644 frontend/src/components/AllLogs.tsx create mode 100644 frontend/src/components/Auth.tsx create mode 100644 frontend/src/components/BottomBar.tsx create mode 100644 frontend/src/components/EditEvent.tsx create mode 100644 frontend/src/components/Home.tsx create mode 100644 frontend/src/components/LogEntry.tsx create mode 100644 frontend/src/components/PlantDetails.tsx create mode 100644 frontend/src/components/SearchPage.tsx create mode 100644 frontend/src/components/Settings.tsx create mode 100644 frontend/src/components/UserPlant.tsx create mode 100644 frontend/src/index.css create mode 100644 frontend/src/index.tsx create mode 100644 frontend/src/interfaces.ts create mode 100644 frontend/src/logo.svg create mode 100644 frontend/src/react-app-env.d.ts create mode 100644 frontend/src/reportWebVitals.ts create mode 100644 frontend/src/setupTests.ts create mode 100644 frontend/src/style/BottomBar.scss create mode 100644 frontend/tsconfig.json create mode 100644 images/plant-it-logo.png create mode 100644 images/screenshot-1.png create mode 100644 images/screenshot-2.png create mode 100644 images/screenshot-3.png create mode 100644 images/screenshot-4.png create mode 100644 package-lock.json diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 00000000..ec43c828 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,40 @@ +name: Bug Report +description: Report a bug in YTSMS +body: + - type: checkboxes + attributes: + label: Avoid duplicated bug reports + description: Please avoid bug report duplication + options: + - label: I've found a bug and checked that there are no open or closed bug report related to this. + required: true + + - type: textarea + attributes: + label: Description + description: Please provide a brief description of the bug. + validations: + required: true + + - type: textarea + attributes: + label: Expected behaviour + description: Please describe precisely what you'd expect to happen. Be specific. + validations: + required: false + + - type: textarea + attributes: + label: Steps to reproduce + description: Please describe the steps to reproduce the bug. + placeholder: | + 1. ... + 2. ... + 3. ... + validations: + required: false + + - type: textarea + attributes: + label: Additional info + description: Please provide any additional information that seem useful. diff --git a/.github/ISSUE_TEMPLATE/fr.yml b/.github/ISSUE_TEMPLATE/fr.yml new file mode 100644 index 00000000..2ff97fa4 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/fr.yml @@ -0,0 +1,38 @@ +name: Feature Request +description: Request a feature or enhancement in YTSMS +body: + - type: checkboxes + attributes: + label: Avoid duplicated feature requests + description: Please check if someone already required this + options: + - label: There are no open or closed feature requests that are related to this request + required: true + + - type: textarea + attributes: + label: Description + description: Please describe your feature request + placeholder: | + - I would like YTSMS to do (thing). + - What if you would add feature (feature here)? + - YTSMS doesn't do (thing). + validations: + required: true + + - type: textarea + attributes: + label: Solution + description: Describe what your feature would add to YTSMS. + + - type: textarea + attributes: + label: What are alternatives? + description: Please describe what alternatives currently exist. + + - type: textarea + attributes: + label: Additional context + description: Add any other context or screenshots about the feature request here. + + diff --git a/.github/ISSUE_TEMPLATE/question.yml b/.github/ISSUE_TEMPLATE/question.yml new file mode 100644 index 00000000..581ac634 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/question.yml @@ -0,0 +1,9 @@ +name: Ask a question +description: Please ask and answer questions here. +body: + - type: textarea + attributes: + label: Question + description: Please provide the question here. + validations: + required: true diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 00000000..594bc279 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,15 @@ + + +Fixes issue # (if relevant) + +Changes in this pull request: + +- +- +- + + diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 00000000..57a22222 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,40 @@ +name: Automated tests + +on: [push, pull_request] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Setup Maven Action + uses: s4u/setup-maven-action@v1.2.1 + with: + java-version: 20 + + - name: Build + run: mvn clean install -DskipTests -Dcheckstyle.skip + working-directory: ./backend + + checkstyle: + runs-on: ubuntu-latest + steps: + - name: Setup Maven Action + uses: s4u/setup-maven-action@v1.2.1 + with: + java-version: 20 + + - name: Verify the checkstyle + run: mvn checkstyle:check + working-directory: ./backend + + tests: + runs-on: ubuntu-latest + steps: + - name: Setup Maven Action + uses: s4u/setup-maven-action@v1.2.1 + with: + java-version: 20 + + - name: Run the tests + run: mvn test + working-directory: ./backend diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..5509140f --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.DS_Store diff --git a/README.md b/README.md new file mode 100644 index 00000000..dd4958f8 --- /dev/null +++ b/README.md @@ -0,0 +1,135 @@ +
+ +
++ + +
+ +Plant-it is a self-hosted gardening companion app.
Useful for keeping track of plant care, receiving notifications about when to water plants, uploading plant images, and more.
Why? • Features highlights • Getting started • Configuration
+ ++ + + + +
+ +## Why? +Plant-it is a gardening companion app that helps you take care of your plants. + +It does not recommend you about which action to take, instead it is designed to logs the activity you are doing. +This is on purpose, I strongly believe that the only one in charge of know when to water your plants, when to fertilize it, etc. is you (with the help of multiple online sources). + +Plant-it helps you remember the last time you did a treatment of your plants, which plants you have, collection photo of your plants, and notify you about time passed since last action on them. + + +## Features highlight +* Add existing plants using [Trefle API](https://trefle.io/) or user created plants to your collection +* Log events like watering, fertilizing, biostimulating, etc. for your plants +* View all the logged events, filtering by plant and/or event type +* Upload photos of your plants +* 🔜 Set reminder for some actions on your plants (e.g. notify if not watered every 4 days) +* 🔜 Dark/Light mode + +## Getting started +Plant-it provides multiple ways of installing it on your server. +* [Setup with Docker](https://www.plant-it.org/docs/v1/setup/setup-with-docker/) (_recommended_) +* [Setup without Docker](https://www.plant-it.org/docs/v1/setup/setup-without-docker/) + +### Setup with docker +Working with Docker is pretty straight forward. To make things easier, a [docker compose file](https://github.com/MDeLuise/plant-it/blob/main/deployment/docker-compose.yml) is provided in the repository which contain all needed services, configured to just run the application right away. + +There are two different images for the service: +* `msdeluise/plant-it-backend` +* `msdeluise/plant-it-frontend` + +This images can be use indipendently, or they can be use in a docker-compose file. +For the sake of simplicity, the provided docker-compose.yml file is reported here: +``` +version: "3" +name: plant-it +services: + backend: + image: msdeluise/plant-it-backend:latest + env_file: backend.env + depends_on: + - db + restart: unless-stopped + + db: + image: mysql:8.0 + restart: always + env_file: backend.env + + frontend: + image: msdeluise/plant-it-frontend:latest + env_file: frontend.env + links: + - backend + + reverse-proxy: + image: nginx:stable-alpine + ports: + - "8080:80" + volumes: + - ./default.conf:/etc/nginx/conf.d/default.conf + links: + - backend + - frontend +``` + +Run the docker compose file (`docker compose -fMrDocJf*%MJ>v+dN`YqEn0lTXZ!OvI}Vq zTaLK&88wa=)|trRwkL3?_7GSfC7i3ckc69n`#)ENX?u&%8_lGX%wb#UB;}R7Zk0 zive>Cl|>gAb2)-R_aO6bxG+^Q%k{E##3-8R9C~2aAbD(lAdx{%JmI7pr8BNjr4lnN zj|{oPJ&JA_6ue~*q?%kjS&1aSs-m4jFqoPZ)#Pq{LUt} zLue#WptBckKxWv?`wdTz7mn`6x{!vp0c4QJ3zq9KScGI0O$scd3>Y0q7u|G_&9gOx z(qShevci;|&GPZg>hwj5Pmz1>qXL5DJ#i|EUXHP_>lA32>DjtEiprDBlmE}`GFY>> zQztYx1;Qvs1-NUouNV}Z(7(DmoydcON`PKa(BGp!`Q4K(>jSG9wB%qHm`o5lj$_jz z+5k}i=2F@XKAr}elCX7ht_o(5xe`6|2}2U@F7PSA_?h7G57oP}rFemNn7G)uvUs(A z#C9_-h9Zx(U5Y|lf+AI%EyoVucDt)r4}DjGPC$9&ijWl+` Ov-4e;h7cp zKm^UTzy3uR OhcTURxR2zc?jD&3SK2HiR>=A;U+ yQ2wMN+&}#?Q=`7o$W8Mn|Q@wI{A|5By|JFthEkPfab}bnmbmqB@@pT?MV+zy~EE z`1U{{mUIu%6++w;=FeO4^+*4-{(Pl)kyV5ccSm^`5pmR2eA*nQnRNlqQ*FV+w#UiP zWQ5HkFnmni2;eG$AuUuOOH=3*zU54+lS!8@mZu+PmA$)}^dp~Ai|&9dv8)-Lc*xqs zm0x~q%somXbvZvUV532cuPj%W0{PZK<#8nNJsJ*{1Kb9WOH>A!|G0wim3VLMo#B0& z%xs(F&IJknm^@Jjzz9kP#RzP>;pSSzl`P9NJ)nLO`NwXNs!XQ^wdls!68|cBPydNg zRJmRc_^2 ohHA@OXy>tWw|5=nxJm0dB zQMVe|oQE*WqWzXQiY$G*&r5~9h@z??xM9GeD?3(&Tidwna!ImPyxzO a(d6vbify|PC!BOVA zsY&$xDx#`|7hg;z<_9qTkz<>SOok-8XmLO{uO teDS|LssMtaF zLi{0;ZpvMdEL4x*+`&j_P&^#UA~RkgL`)%92;`;O>DdpVWKZQDs2pqFKK+7A>kg_H zIs;XuQ8Hrg;7gB#-ZdAz^f7P>WI1JatACM-+1_COIcb*1UfY@CBTiO&@o{odGPx|H z;Pg$-p6z_?q_29HvMUmo(i%tu@EaBd@iX+$b7bEMB0xwb<-YsbGq4}r5eW5Idh+Jl zjh$ B)` zA6L~sBP8$09Pu4~xEev%oh>12?(jF`kU*c=L6V->LB92a%vD{6r7T`Y@-2Jcik+p# zB3_`*DcgOSrP|e|!_oYV)C)5S_qrmDOnFq-TArBlic@I1cjo=V>g9a-B+P}vus w)O}v2Eyc$h;WLatZ zXw)1g>@;q=@>)tE&)*C}UhWG6QwE%FTH#QDB;+h_f91xF8#H+X{W_Pm 268LZaB1>?{+G^zykR^O`A${6+En4s)g5T{pKj31~KThn)AN{^4 ztM$?lH2h=Mf1LPVpr@_;6cSpyRd}pJT)O5{tBFN53Cm}~yP!)xDsC|%ID!1L3O-s3 za@~*=yl_w!&u!L+P>NmFUtpI8gW|skZ}7wd(3O+vrgqWcxvQ=s8KCY+-vx@E=T&Y? zSvQqPV8~}yz5EwGv`vttB@?pkvi=uMELXS!99Q+CB4wpyWPEu#_bu(CJOc1uGU#g4 zE^o160WI1dUwgqVjdDgEU51xQC~G_0(Kd;z$*&clqO8^#N^|vXh46Og7XL_l53Ms# z>7npbnu^bnu)?F|nDSEM{@D1^3fnc2mlpc47#4j5|3 )Dt1YZNcNT>szAmdNbjG zmk8k$#1#|`KlQNiBJgD74;RpP0*7iA2&0CB4>WwtL<6s?*E;R6h>iCjS70T+2$1G} zJw|;eJHb#KFz0Z`d24Jp-+m9A+?Rf?vx(8TN_{xQ>4V!ZYw zhl}h1(i4@)SGLE%Wi~jnz+8lGtKzdRX$PPjOK@kFm=WYxNeWze{80Vd>3Me)cU+a; zC|k?Bk;;Q6N9 @^ahKBT~)%18Ht&*A@mdmA4V|raK{O}6yGxaYt5}X#DF$@Uu|0y z@@8fxS}gCQy#+X}%a3O{Fn?@%zBC UGEk5n< z33-+U_?ps~iF!A5iXswU;f#hp(lt@E24FwUt7l{v40=(OVzZKNtJ-Lv4aslazQ@hq zR?8bG^iqQm$w@Pa4q(IknNjV}+f92Rt8`3=$&WyS6mg*=%^z{)@wWkDfGAJ`=tE?V zqTcDCB!LG`{{DFIvF}a^-?)p{-TklVG+-rLQeeOV2NqE%7gOhRoMQ;*^hCVQVQ()i zxf=5PsSM1A{G;J)Dk9m$91t1K_&;WDWX&KeNK6J<$P~Uup;=F*{CCz$vbB#jC1I<9 zJwBw2otCVR<6=VHgpmn@q4A}PS*5D2 I{3oEO}>4(_;_AY_3qNgPL`i__&( 6=5848(*bITRsGDn8y zkPFkaP77XU+o(`+^Z(m_r^5LOk;FkQ0ETkO&PqM-kIBU+wKx;QaZ)zt&XY7_B0>{V z&~{0~4-hr_*}D!KW3x?xJy7#6e}yKJSpUCosWpf_wBU0^P}E_C&^m?%Tm17J)q|a! zBp LF-ZGwiKz)l>D&{WQtMF@8Oa{Nr4fMj!D<9Ti zI3?|L(z*8vxBNj6OtX76he<`IVt)IjgQV>SN1Vxm1jUuf?|*y-aZ+kKqz^e*P02&p zh;Ry~7l=8exJ?SLLO#)^V0(Mbw1eq^V=N3aW+;h#CDU1+g43)2!q1r!7;%IP{35U= z7aW>us{A6DH%H(%S(x_Dh&>a>P49!G9}2Lhu(Lz6m0x5`F(C>EKfM6R-iwzdU(S!w z{Mi)Yi@zHAq(9&9xgYxg{tLV1iMroiC4&Z9#;YG$UkZ0!@kbU2l77;bQb(&VIks?u zn*5^NtO@_HG|ICyvuAMg>sNO;xxy6DJFpWHq~#B1T1Ab1tox4CWb0RWWnlojBGU88 zgs3nQIH63?D`ZI{YUf~S9xsu;6Z}g_iSo+lEdn%ST3^xjK!nr+pnp~$Eld X*vAJ7ZLzI$MP_B& z)WSNDXeP=F90&lOe#ym C*KUm13DCPEou1aZ>6TeU)@Md79fAM*paWtOw1IltB UHE zIxB?CDQJ~YT4jJkvw~b)q8W5H-LO|6fm8jz#K5Y{x7z3Hrl+34)T*olplwAWvxQ!F z|7Bc2ixaSUFMe(TD3~W*iTQ_NrOYE`(*mP^&I1LqmNxMhmNR8#WE?$8;tF3Ds2 5Fo7WP(cOp)dZ^W8I}Sm!|cT*4?X(@PuZ< zyld-;A?V8i;F=F?oVUHF=ooq>8N7)e@9Tfy_uxT+2M%QjIG=*zIAki*Oq>_7l5Ifr zi4EtVvoBGS1ZZd(%IN@R^1?OfXHi>XPziKpo#QEH4yh^B{n9o&&SqNzM@%9(OI-5= zxyPe0DfYml?jDel>Xw!WRt#2WgdjDMu%yEQ#6aw`PfFdX!_L>&Yp{dFU4!|V6%KZ( zVlHrrcKACcEQUftg-w?jvr`!LIVq rR$U+C{(W_{pzxWURKp!1g_NvK7qLJM4hGX* zM#X~Koio_P`ZI2yGm6f%2=pUQLWril9NVEHq|_FahzkQg&oYy+cKps;O4yiq>L?h2 z^K|jVS@S`)-kjIdmNpdl;&b1f4~+>w7EgFT_R$% ao%g1=tNZXIBvi@TmnC!a!-&a)38}B{I_#@Cnd*!@69cDyzn7LJ|6O_b zIRp7ws&xb12jBxM&di=61;-2l1L>cTO37L9JJ3uW`Wh_633ymtg;K$_@A^BP+;0~u z%*oTqR|VQ4_n6QeL;}MAz6htr!D00)k#KgGo-8Y}YBH07AGoMJ1kK+kt?dHIoOHBk zt0cb1O(7!#MUHy|^`4&loRM}}0q}SViReG`NQc=aBELl1v=aN6n0T;1{SM2Cb>Y!E z(`~_T0uF$R>}lzkSdYPDL}$c0;w#nSB`u!Wp3*-<5Onbr6QXA4Dl@`VahR|I3dIF^ zeOf{c6bq$Bhlz>;D)KRu-Kfr1sV>y?%7+gh&VIe}I7c|sGq~e&dJJBrP(?8Bkn0Pb zIOV02Zd=|$;crDmj0;ECu-60Ss~ZrVrK7^Mj<2{WM`&B9`Gs#;k%JZWp!jib+K=Gt zF*`k5n9&!xV`z6wckF8qUP}RdAGXpk+1Oz#|B9t29to}}I{Sj{Bv(_w2S3Z44n?qy z3Rv%@e){m;_it*qzMviWo 86ag0732>sKZ7|Bp7|+=3c{@vnQk;xXGX5Z$g0U47xq2)S?*vCs&iytG$TDi z?eUQ<*Ukr@FTAe+xp7TUhwtuJ?MCdE&%wl}X_lTYm=>cfP%fwQCLf}OJ_8QBs69?@ z)Ki_akYyDp2BwM0jv^}|{S(hvD`%1xavZ;4;z7w{w4soh7HpkF?4C-j4{U{ZvA4jv zLGN=BX*p0CkNRMz1fGH-`C>q}sH?lEO@V#T0xWF{7(AvXCU^5LTj`hSLH+W;r$m_4 zE+7dSZad1oT?G0wPQsWPj@eR>^Uy2|MDa=XaZecY?XsXCu=LLQ6t90CQ}}MvC2F#W zE}_t@SbU9la`J4piihyFPWD<<>(NdAMt%%;@9g<>dZrBWFtzjVeERI(Gm5rQ9}F>r zoCvVRL}i~>;7u%+DI%)_+7c40){C%(oI3z2va)gCroM5b=lz#Gd|U~qer^;>vVA@L zyr=BWNWMI7We6M^^E-Zg;L09zmihGxvcM~97mB%?Llr(R`ZNymtg&(TU2|P)HM _mZEuH1$iO-~-jl@$4(MZx%aK zv3UP)cPRSNW3SDQFxy8>{3_^YP+6`49 QlSwEVxu)*aMkNN8vXUDLf1x%56o9cxp`~o7gPhOSyRVJ0`qv z1)B~jCR4r?`I^vceJffNCk>YfqTvw**k8!&j{cIkr&d+G@b{Vj5QE9|=_k(C3JQc8 zZ6Yt+=g*hg;agVyem#6OKVe5+gbkN_snq($rw(Cq&Zn}ffr`1`Z_JL3##rUzO~SC7 z6frXuSMkXGJ!BcA)GEg~%5sw*G 2{?5n+gk_@ZIN-+@_TsC=hyvY+0T?+vyq3!EbG)#nS)SRXd+@ z39zQ>$0+wwSMuVc`}qaPn%zU(6xH6~UeQW-Gx(9kanByrv;g-SqMLCh7ZeDG{q46T z_VPEpKc(ye-=6C>%?IzOY34v3%?vz`nsHS17KYHRTr6e@gPoSz#oWKdu>f@A>Er3( zC?!_beZxdpu?+|#-A4UA=n^cxV#I(@o+Atv`GIsB`R4$-G0oHyVLof8z4aZVoVzhw zhR6aJ2g0-t%ru25O2FHQ|5mbyF4zdJ)F5`kKUA(7YPmh#GyRqP9a91*7OQ0Qj2g^a zW%FQ54uO`H*alI}1SlO&ZM6^dZVP|MknvZRo%M>3?0k%#ttP6+g1fNMBGjjF0@EW% zg|XCx;MxLeyE$+xr?|(% DY=}jX4)QHs4x0 !GLCpA P4na5f5HVd}?R$kR@rdPam3B7LLu`sX`6{!cQAbZU>0 L|$z8ml aFm6xc`2V`A}# zHJ>3JXbvEP&s0d$$k0b@III{VQou$f2TaQ`>q$1pJ)UIZTG=_pk)@GU>&Tm5CHII0 zjX(9I5r=oL6&o~(t4cK2iHMDL(pZZj$b=BvAp8~;_>34RxrI`VV1AXjn9=JM>_N!{ zTKg`D=R=H6W&uBGu|D(^lp$6hsv>T?bb ETkrP@uZbC{TP;8z}MWF})^FDXz^C>D=IO*RPA-q1C=@4Osq)E2T}!Aor=ETo}tOaoM$ zZcW@BDOArNslT&V@o@k3h-c{YX}Ys{Mu7Knf7Oro^T7^S4DkK>cnr~CEuKMo!X8cP zRl4Gj1$BY>ck{uGbqsk3bqE!@=$jk;UMOMd$F$qNf3<7%E4EjMH3Ptu-Ar(1FWnsG zp)Xax>C1HJX$GPSgCro1Jx7yL9(%7sGZ6<>r<8^&(n0!Jbed%Eh0tT{Kq(SlG{lkV z2kI}tDu$gVkEQlWs<;e9zlvHAjoLFE(%HDSQ~Dg#E{lOv2#PghycIr^K@*=DET1p> zhhBkemES}sqxH&}_ez_kiKunxIJyT9)A?{=4|;L~=71@ukpVH`^w&lOoW>)DiLBP& z0+-0c9R~nc&j?qzFjZrzf2%%%koL@zSWMJU_Gt&*w}o1G0axipi1B90y8G8qel z3g+=pbv}|}%B@xtgG{9X8|ggd?_VOyu{s|vpf1b+JLN;;U*d}yk 1yTx?pb_%8ZSux}O$Z;j`_`b!Z=2C6WdPTLh8Io7@{Q%&k9AO?<1ANl z^FfsWHqLgtn w(DHpMTK6S zWeL98vgtrQ9t{oi11*s6GI|Svcf6s+OvO%(VTU*gPe2`@fE4{O2Z(}ePCx8 QT*)MVxaEn-a8uPa~Tk8@QnZd zEM~XeY9!Ykvz*rZZ9~5!#$gNHy&os{h*X2zi#v-);KnQ#abu?l&JI+P+1`qvT=-Xt zZhqWX@J$h~+zM&tqtXbuP0tY=;rx}VoIE7z*U%fY_MwVeJI$jY&hU1=dY^$J3<>5^ z!h-{5zdR;_mz?UJvcD|Za&AqWGMUm&)>nv-)* ^}$B}@99-adnCu$T=Nxxpd z$zg507qn}9?tOytblbtGv;Vm7GT*mbmv3zj#x74Y85zFKb2Tt)1LQsGrXH>dDNh_9 z)axF6@2wbHA4QF?4`AN4PXq4OuC=v4UsaX3HnuNSdlT|qBK9?zPWRU~31jtmC)+%Y z!Q>>!+MWN7Z%Ak0RCo24HJ!=n5X^`naC)C(*G-<078>=4*nex7;cG>MOn{P*;NY#0 z4ddfqZ&c5@&yrc=Cl4*_{ba_y;=Z`-eo_7?vsI(rxbgn@q0(6iHE@cAR|TZS_Z(q7 zX8jL3ayQ40Hv#);*<1GX%fQ`f1a6A+mJ8LXQJ)_Pd_(*v{Hh $!M$G12TZV-7 { zxZtfMf*C~2WC`A(O*_AG`vIQY3^n6^YgZnKElrQT2JkVp${|PI2Vhy!dM^S~ZR_{S z(ebRCjzalY2*m?Av*989vP>>+>P+X4Z9Rc|O6SG|6(K8X0(29LI=cIcu;C8vg}T-* z-aDwjz@s9jqJ+N;&YygL_svx(bb0b{y@(0vi`(r)t~>ISV?e`h=;SsUMGvLZMlB4C z#RBe}$re|^-Tv5p49X0AuWK^$CI!5{n3D|CNu4gda<|9_oQ0rmzbBv)v Hqmxd>_;|0D$d2>W?E=png9SVPpUV%{7grrJHx(P^y!MXMh`V8uC z6}=qqaSqO^KoJ6h4NA}Eyv_0u(z(DIGXs2$*`>o5gf=!{d5F8#BrO$SM%L;VAqbPo zO7SIAW$e*)S*@91)3u*fneeX8fr<_wj>Rgb8D}<}qc|JY&7fD{$|4$3;dO^uv1^#V zV{~B0?&EE@&`%rBDa6#h&TC`K3MR; -Dg6#OgZAC^S zg00^>|9inRhl1yAaV(CCLd|TD!8mWN?UM znNd6H2&YLd{{{P%-(*aAh(X{p#(jtDjpfIjgvJfodf?YxZss$lM-q6S^A$g{hl;mp z<>ekOt_Z|gt sl*O+kH*ljlK@`sERp3h4i ztlq!jcj?EalQR;BY)3E>F$=;!aXPo17{t=2KD=fy sw%LD2e7sDV2-xgGdkhzHRg_!Pf|S?cj;C;V&fl-=(6in^G2;uP;H z4~9DoZ8W`Z_!QKiHh67Dxp!gi<|aLE^KcsRp3TH5Wz{Vd(wmTL_R|aV(g^N{d>|yj zr#j)3;x}-A0>gLhR4AERQ2zl2mtCrw@AgiE{PQ-Tiign9!|sQ+7hVby(BD@~{WME= zFPfu9+UkFIegYe3@bs>yYg}ta$Hr q4J3oBI z>v=1T=1JH!KN;}E(zP sh718db0b =~L8PNd)ony2U=PXP6g8*>hRX=3@1+&{Yr_?{@hCV&E0Z8w z8D7FN;RHf+LF$e+9BP%7qQAbW@8h*_r7eBU7IOdB2PAg4yfesqww`5ft8*}5xYO2@ z-jU=hcF}~l7rNbZH1CUR*7^eayv(J%fti8q@zbiSp%izaQ5J4qa+Xm~=8i;u7uPXA zUv 7A{y^xigd~4 zY}L*uNjwYK8=$$^`hdyCzqUBD5jRwy(q#D*)PhPc^GDlGD3j%R 1Z?(bUdrk-S7T` z_XEmCl7O&2D6&=aD88`2SCu%bg+*P34qe{m+Irq_To1+swgFtN^qSM|$xUov<}WCA z#l7c3!RCo=U#hb)s52_7AG{lX Ghk98h`DfQ|4ivb=RM5p`U@KYd-+}NVc6cPym=n@%y~3H(oM% zJaQO^LH))XwL+7(f<~0Ytgu>4o91NvQF-EKTew`wdk#k!sh!O`F!7Q|$xgY5da-mS zj~y?s%=FocsrvZFRwH#F)=`g)pf(b4S^-Yy^0=1P^5>(iD@jCt7!Ib*pz*&mlc68z zkp6Nh?m6v|SK88Q8w>MN`9Q|@^d44X*S)_XaA+_hBX0ejHe= d)8gLESiiv)aIM7dT zb3(v3cM`dHRR9|A5b_Akb OMn9Sqx6Df2vu07(EM{* z*NtMfB(F-*^}t=ukyXd){d3TEGvRHqsqzH<#w JU!&B1y<;TCHtrr z|JD6BUC1v0d?3FdA9P|KgEFAVzlSt#zPti82#MjO|362se|)grp%Dh+fcL-=4;*R< z8S=hY-9J|XDp4FV9gTo~KbgTzHP-H`tKOU8b~eXH&oRllaV1ZW9h?3>?ln0n)1J87 z^hRBBFvx&Y>yC~d2S0sUBreJR*WM}jG>`1h-Z5NzlYUoKr|Is-S?LMVw>2MoeYT_b z*csyr7r|cCym-G^q@r~*ta$yx(yo (%nSb4?KP! z`Q?4WmMzYKh=#6aob%kSi_v{11zs?XUj>u64Ev7K#_f*yuWk$PP9LKzBPX4=5$aFw zMsB`L@c*5AcId&+sV;PO+$1XZth<#H )m$3YE#>~25r;^t=s;_=N|8qIY0EPXCOD~ zK)<>7$(!IeKKLGL*!C+SR4{0)I<7Qpzzo?ICCT$Jwfbql _Z)2-`o5yGr%3ge#y93J@hn z+AzN%)sPR~(mWph*;w~j a*6x8>u!xEh8gghV+F2!C$D$iOn9A)3WH2@JDPDkyyW4ZwPm{A zg|PTQ2jiP|muus^Kk jc&4H*2rlNMNMo- zt*ay<>}LGeEFG`s%hZ(lfYIlIsz%7wm_N-5M}#4Vk~g59&rJ0b-XEu97ZI3LITj$& zt21);{@T(fVV}h5oM=;KlQBsgbgoH39``Jo7u*KUPcV)E= F?GjC-(PGrBm&E={ztDQZk8U%cqBBj7eISl#I$3QfJy;}EBB*l zMnGOv*ef?CQ*N|2(5g4}z??r|q7%Sp2~|&4Gvq-|^QON%Z|U?LQEm ^Xf%0EBT@e`p56$^|4 z&2{UjZ|Hyj{p)X0011#D|7SZK2Hwv5zyAtVfuG)i)(Fv4(8W`~2=&ss4 O}8s@-?i4mC3Cgm@+@`$MI{U4& LxR!$N}WRK%mhaAq~9Gv5vb6vly_viQh{r>jH;pSY|>-Bt$ z`?KFHJTN%*3MPW>xl^@#bDrf@n%n$MI+~cV=R@PHSnH&`*#`720us}^?qcKgUjxQ9 z;G{Y?Ct ?@9U{xp7P;LW7{AFa59nQgPt-nUhJ|9fIbr0-s}qpF!3+$PQy0 zA=7#NTlbV5PZFT1KzwbgZAh%4& ^VEGo_cl!5C?DJ0;RgykX3&(Z7cP~XJ zg^sO^J~z4yeB0+qeEu+b$|rkq6ZrX|Y|dDyH^&HP={;OB0J<(C|5yq;&uh+TibdS# zS;-CN<8B($(iIS+AhnQel8~lHT`O?oxyT%D+_6K5hOR!g&{3LdU;BGh@U>BEW&0C| z_{-M*N?7574PCY=&jh&_WEA5n7O%+VfB(z_NRr<;NqS-Q_#^l%?I0b7L ++DnDXy|5a2a7yT6h)4?F# z%~03KdvCJ?Y?R_gBTsi^8i7Sz(94X}YN5t#^fJVoN!yB3LB@e=+la%kq*EPUyA*1) z{O5IQ;tBSFAX(iHrK`W~N1|D-114e ZAitK(+=%_xuTLFw|YEx7U#*s6CbHU@@!-LdoYi3b2!F zbHFX!WqSens`JY@R|k7z)07P&{@o|&Rvi94{CKVVr;9xD!7>tI*^2dPUDy9GO>hZ4 zhn=*a@M=7{#(jpQv|wWjp>EOpT!vd&S-Ptz@Z-K&y#Hs(e6x@9z|7lv7Gj=lNQHf+ zHT^VR;Za|Zz^^Xe^G3#vedG@K+`qV&p7w38#+KviJm%ruQ`CKV$W8pUqIGGuJD3EW z&V4>|Mv8)TmPV*%u&Qa^ZJ8{;ElmchANm)<3>=0IFx8s0gdZfozq~av?hcs`sV>R> z%QqODzVKfL`M>nuzj)eziX= N}EbUhP)j zlRNl20@X12wANAEU4W**M9dsF^;6~eZ%d&}!LlUPlU+tpDs{XT(av?Y2YXh87akOz z#JRY9`{_-M+~YO(X{I!QmDb?Q6#xLEsNGDC1p;JAI@YxL`u-@37eDHDWnxcc8fSYy zsV`?XVH5RbT`3s8_u~Q!MY&V&&Iz-o$}9gqmD^#~X nvp*6Fml1-R>MRTUVBVd;JpI@`pN*Ru1e!a1d1V7!`FJ$`+TDvA6=#7`QG zUV}7ApV7(+n{k(UR=8VnanK*f3 W^(!joRva`M6F45Sa?5`QGxNeOj~vK(^urT~TixedEcnTyVd&BD zWUDOcJy~kvV#@skF>9|rt^*x2yWL^ghXn$(b=Lr|i6pfr?^Tnay=|yzIyo|raZRnH z+<(}*kPAZVt{ODHGwQpe4QqAK9y&ie0=0rCR@{UXOf0?Qh^S5kn$pAZs_wobt7K|t zw5YT>?)rkR3r%@Kf}J8(rf$UvAw@tv{LzXuQrkrGe;nrZo4ep1qlfJB=pG~wM+ z>D|H@uIVh yQWN!d*68#6ad55*uT^7(WdD+K#6ltdwVbS!Ylx5v z`5mhn1ka?HDg8&p-HOf{E*3m=$E=rLcVJoHai$y@ME-pJs=&5#HH+L*88Q>Ka;J37 zQx%k?pG~Kpj RHzydU ( eUB~Gkup3ah6z#;bY&fUS09>tacy1 zq%Q2faZ@1T9vH?Rl4s5)m3n4*)>fssClE*WuqE(C+Mq|Mva9*7T#*;P&P#{@j50XL zMsxy0P^3Sc^( cYks{RI{# zcS9;M5|FQ!oN!a8y-IM #qa(UX>x-Hx&4!MQB&)2RR2 zoG#~IJQsJ=5;&DAGUIx*T?;+7J9}-q;lp#no%o20c;~CXo^d9gi#{VI{IAN%-W@h8 zGn)7-^5IX>^{)gpr-g=|DNYKaG~Xf6u_`>5vR0dJ*vgqaRzCHrgK*zTk;E{JHaQXn zVCfP9S0_}3*B^HQ^PdF+$bZb67A%V*1Z= $(9v7wMY zE_WCKMk}fS6H>Dj=*)1BOxwVUeYZx;W~LLi{@~FfY2t0MGFEQ%0&^SJM$%nG0tju< zDu>DAays;Fbz+-$9o8$LpS)djMQ>`fh4r|E&0Yq^`IRDKBj$UNFDznF1C3b Ky+F9{PjIzQxq6g%Y = zYQ+`^{#b|Fsfhb&b|Z%Jz=u|Pt$tDYYMrC)#KR7e)kbgWu^uRRO7YE3P#&NtGy`<@ zN7OLajDkB*LCbp!y}2C3nJ>QxD5p^T=!mZkGEr{{pBzZ1@L2i9qW7aBe0_R`)we7m zPGxRjY4bphtJzv-?gUhl=|H62L2a9=`x86xE?LDM5Ie#(E9Sfb+NF=x3a*!CirXjz zGR tH~Lg!*iNYj>&Oa{5bJUvMW^wD5f>4ne(J#R zHm>OSOfP%yUBDlmTdP7^ 5MLQ6|2T(i zlR!I+WNI;gd&wcYbJ Vs>?+MrKaUJs@as}Gr^Dec6LW?3T5 6Akrj!77VZA?Yyp!rb5Egj& ;2^v)Ly7^j-zse0dvsVva ze$7#x1Ce*YiX?sGIeT4<|L#cA_}F;?bt?+aD4)2OiCk#Iu5LB1Rq|4$ Z<~3wGpqd|E> Ycd_GP&$?>4;h?1@69ReJch4ss)3owu)?$?C_Z+Lp97h2u8G zUc(_lhMutT7lPuZC;i8MpOzn9jm}TmLSft9^uynoGdi)jvmvI0x{hLaG>uF&Y^t!K zlbcKiz4j&fhC7}Q6Sd-=HVr*l=9p^Go@%fG!M_&)=?|K0&tg`0{ovD8TSg|lqy@IN zU@BMmY~1h>%;M_h{wZnu^&>}Y5s&V}mNq$I>PgYjJdX#Sq+^yt VX$~iN{PL_cRP3=hDKGJH=DW_YPme$c} zM6UcI#`;bW<3xT=fMb!*6N%*V9}nmk2FNE69bqSin3&$-JbaSjsAA}Bk@~}Qq eRMrRd_^gf=JURjh5SfX(p`Ej5j*?vRxk@PY8#7`aX7r#M3W* ;~DALK$tAAOsbtE{v>k^m0#ZuOu*K7KprVp_*?xw@-MmQ9f&G#>wa@unLizp(r zwT)+Ay7cV>3Ud&u8#InyM4xTC_9=5O1Ak2*7p?2L?`P~Ep*CuB$kyX)ZSuzX+e)cC zGhAm?neLmTsB@Eba#=4PU>OHaxo3woJv;H!cv1Um?2bJ0<*7&W{x2Rs&4_(Bc_GL8 zlQ3YcQ*ZYJ)kN7v|NlGs-B#bB9w=g}Ve?>O_03L*L98v)$;y7y2L0hjpGqIDJGNhz zzOK9P&*G#@z_4s#P}fEmqz>PPO3C` K9TV*v5Wj64EuZbN5^xl274X z@JyKR=+U>Yj2JV=9J~03IgRQ k^278nVYVWHu3!$G(FcoWB2i<=DEp> zyKA|?jGd%!hS5f)4I5{eY) P7_}P@M!{Z=L@`bX^zh2&s ydM{ jW8(4no zm=zL{&p@udUMaR~_H>NfOGE}{18`J!89ondy?8^;&NOu-M+W~LB8G%+p%Jn1$G8&< zdBCj+Pe=K*V(~I`GBkTGY4u%{-dH6Ra@>g!^+74@HD&u$|6d;-33ZBWnc-GVqjk7? z@L1%ftYd3@69HL<5oruT)(AdmLaSl^@Sijr(bz(YcpAIpZ#>5oTa86x0n)Uoa;h`@ zUpkE(`g~2n=p_G+ h zVEIRLwV)RBTFd)|l++9tJrH CmEhhUB#C+1b}Hwe?^khZycjECis znG;Cin7z@bkDq9(V9+4_hYy-JhbxH^^Y|E)Q5*FlvZ-$md+4j}V7zG4IP7b=^UJNx z?G~d~6XXBA0jt*~HKa*U6#tqln;Ed3P&fKCEQ#86v0^v<=sUCvk#JdVc^w_Zbdm%3 zTVx{t@B}pwO*QW&i8$ORo2MHBx8tF!HIvfLHo+&Q2MFtzW-=gDe| a!jMWrY?+!MWpmU3zzZU>77Phf|Rl7m1*=GAEGd=_8F6ZZcfNa*ilk zm1~S`*tOdYkej~E=o5!b-G@k(_)g*)dgF77i~?QFkBUXd1iB2~_;&J1_Th7P$Hke@ z4Wg3t7g|@4p_iZ-AP8=^W}3v$2`TxNy?KAJk~$`@`F<34sbp>K1kv*dqC<7puW(ux zPU-~^wl-QIR^5YGjb&=?nMrPPR(&|*0NDzdqScZKdcp!iRTNUar@koKc}9cnYMr@y zSH^GdO6?f;%(-t=7fqh|=mYA}5l}~3@yJjNNvOXxO++XBn6>Il2MFgjJ=*6Ud|nj1 zUsd0a(LELXix+`&@V&aP zd7g<6tMT+7S?JVvv5!8 zbms*~I4B*I{UiE+KZSc`iONjw3wfU;oMKp*4Io46g5 >4NQ=d`zM4 >On+|2!CMD1lbtrwnls)OE`)$9xge|1^45Irz}&lpvx3sU$-|1rH@Bs&^a6HZjD6FoIZsaIQ7 zyP+{_=dhEN)VlFWKr?VB(Ec+okwY!JUhZ!TlVn{6U5s?{_)@DOf{_bAnu<1#t5cBY zTZ#2V)a=5G`dNGK_oUGR(dr%<9=RKJ30c42WA;UTA1q(-; %`94UH zwQuxo7>n*u nVAed$DVK|q|a97r@2fu`d1+p!tXvF!8KtOq9y`4!--YB z=neZn3FXH+2}A;VZy21SKVO)W 0~l zDi=5wwLjlP!W8qw*HkLuSed~SiS3P ~KFOqmst!-ZYpBPzskr`<7*i9*P!Jnir z)+(Hh=ZvC$$Z}%6MWbJUg# )41jQ`r);_W1wGopXlb__dax!RoP^<866dDpS$lT zp!-4d-&>wtjpPX@O)ffZ5XW}uh;JM_MtZQCehex^N^%heYt`WRWp;@1!-C002jc1= z?qSyZ6xIHSlkO?@8;0ptm9BtnK#;k?0FJypF;TKQ((xLs`vo#^(&c{JT#cMYZz>ao zS)P6N(Ch;yCPs|I?X^Ry6Q+NFl$^o7yerGICXt`V54$>2{`6_im^Y@`LpeZ1?2QBY z1y5c%baou86z) )+k3sE^;(wo&IlPk>zSY%R??Hpj*vaTg3Xi1-E-eR?q*6;y=d!0+a+VYA87JE0*a!I(ViPO4|BSU}X@d=+&~k zZ^F4yq22qXvv_D}%gCJQgq=%@74r8M-W74ABM3w73)Ov|B &tb!+? z2Ew$u@vabk&IWU{2@aH2Fk=B4EvEnFndrHlY2*I|i9;a>cH2jyIqxYXeQ9{2KN3)c zk!&%n>LgCy0J6MFF(w@sX{R(f ;7T;D^8W zMNwzCNn%*E^rQsZ*ntr3O=?R3XDbl05LT&aaJaakBvY)QE8#_K!VM};BJF !Hte0S0*e4&c>a#nzpXwONT?Y>EB2NeDb0gZ3ZWmywPy $e#5B}O?b8{zfM(NOCtjvG)f0)?g{Vy@;4D5gB zzop4cGSsE0Fpn%*Sr4SMd2RmT5Dzisu5&pl!!3WkO ;BjxmOG*c+D%K?^JpIU zG6~&m&skj0%v-t2)0>d9Sn0H|{dx}CoC(GUoBo+K!s!I%J~iJB9>D^wSLdD1zNA6I zQ}eTYKN87G&&17o>G|&uDC#R+lrHQn6aA^JL~MRK8T9?tn~QsZumQ4@=<|nD4oSP} z+kf2gR^QZ*`JQo5de8H_LYC1=W%L{C5I5JyRPQILcV_RV30&!N!-h;uy!p+|J$r-h zJ@TcoHw<{4mYC`9^8FFLhx9tDq%!A0>rLl5q;~UM6SDi%+$mwWJg6U-ZQerkow-3_ zs0n5xc+kOC#v!n=S&=$;{T(>H*&56fE%6eWT#0&6OW!v{a^UH^a~|+pjB91kBS)Uc zqkzmDk9i-`*<`MKji}d>bYam()=y3_NQEwK*WXoV6vzc3tXNYea>fJqu^ZOsjGd QfV0nRf=a0_UeQ)(f-r1Y8J($57 zs=EqfprFWCv^A-Xs|Nu%zXI|bt-pM2fU7L|03Gdn qrr!CpdE-*Co3pwX|-k*rZOM?&w1^OirKq^Yp6} z-+qQNkE1#jS!+|D6SA?cI4QfMw5HBE0v-{AeyvO{8yi*s_Km!M7i^;ai!uEK-^PE! zqH$ty6?8R0;pLGzB 7}|TcDVARlTCK%b_DS0k_L3X7 za|29vUgQEdU%qp67`wA1IXEXaoysx&by~FMKonUo_^GV?CK7KnbUv+lu*aokO&klY zV@^p4%Pwr!$uX+AOUgEjZf!r>O%Jq+= P2GD)Kt z6`HPa7eCmC==#8f#@)Tg&P|nW8NUwRGj~s6?kCM}QAy&YNYd?{Ele9TL_#VvC;7Yc zSs?;02dNZA%{%ABYU3t0s?|;sos(`$kIVPVGV$f%m&KN_z5QO< ~%lf@Id11PQXl+DGY=_GS6 zktH-cFQp-+B`g-W_*&(|2T$?zjri05IP-}r#@Te-u|9=imr{Ib(LdB!jcaeYcA9%8 ztacQD9`Ro}{v2}0aE<+@oEEdOa{#;5ZsvwjxnTmd`u^PTC)?T|myfBNUH;a#wt3Ce z2sF(F&;D(VSN+Jux$b6_UIfXJ|0QzWz~`04r$BYq$XnloigyL*NToD>jIc+X%@r1+ z9O#5{9%s8~^LHzm$IWBlv5dU2itI)|)aW-%XZ4oDeax%Lb-NeMmr W-TU0f%b9sD@1P4O=(8V_{F-P- z&Fs{Lc%PMNsz~0 XMA?|yVfi@^BHcUuvlUNlYT d zdx*$fKLp-KhknZO=L=ZrgCm_8pF$#UTy-*#si(VMU1StzAp%($t&B5sxYppcXQUXL zZn~fJTu;b@J0a1y7^?yLN xaJofC2%sB`b{uE zZhOzg 9P7Itb z&rRt{Em2v3DLB0JD-r_GrVWqp;;+oBvwK<_%Bb~k*U@PTadK+*CzfwSK#gkl+g9dE zxi?Wh;7J$dlU!^11ymw5CXkIRb@rMG8-P0gwGgSmqzp+P!`6+Ie%>ebVP~*raA6B% zDmlSp`7T(l5Zvb#@yIfmFWvH#@}V1CXxx5^MzX@A2~VLQp6ijIsTl{pc^mo8A@1y1 z-+AQs(YFl>57CXsh}%lCd#`h$8*Ksh(8v}+11%fVP-sfeyhNycv6cz@7>;6d2d)RO zTve6pY>7S3Z%9BV%Nl(mX2Q78YzS^tp~bn0)~*pyg2-}A-b22=g!`2k)~+br=y4=3 z(sY56rR(Liio>>NdwfE^GZhD496*lC5}$O65`}~|AlSK$QJ!i0tdYup_zj$E=|UXl zdFjGLM>fpWIMiIpG2FWda4|EiT<>2d<>suxN!D+UGm*IhO;eRK^iYMfcRALizq#I8 zP~s+{;C|3AINXa $e9_O1~QMD*U z2SodOj0}_}OzZD!{E1u`{35dGLS0PJ(ZA9K9igP@;JENf^zBy0(eh(F6eC!?trfTE z1JS=@QPTQ7D_1&D^wnAcbuxTSU*WP4n?g f{==pK)7K^l_`8Oe>3pGD7+ zQPN9#odhKslbwuGwvQ=<)Oh+TRdS4~s%}^rOi!3fM^Ufz87qyPhA6gcD_-Q)loYCD z@OpckkUYrFz&^l|QshBn%4scS)pRq6Ean^N$8lB(isR+Dv&D!1jtf7f#4W*L!F$LA zw8^6k-zOV}X|)oX{CHfK4oo~d!JhKN#ppgFDNH9g#4zufg-xjtkgg87!S;GS{)1(3 zoV>)Sa3|v<^m_CyQxgBSanegMRRI$?-PUvE%~J&;xwB;Xf|32{$)&84@9h=+Yp;ed zxj}#3vchm`cIKsu(&Jn6-MJMMtW~ztq(7SF+Sw1*FufY}!!~~TiL-va6wQVs05m`` zU W*^x}|}Ng`d;&=r-5qDKh@ `x^Q+{W3QtG_vO{! zd8Sg|Xs6wei$-K7JZ5fXoeS7lCI;Wi@~TL@(&GLS@9e{Lhk|=zX1(jc!~JAKlG}N( zJhe}Hv$LryT80LF(U|Sq^aYt~WOP_+T)c`;F30X2+*%7NmG@ zTQSZ@=zaQ$<-|Ln@DWPkTyv*Z$|cuNWk|V{3=0>!0#^*hxJaCJ;uW-?rNco% G( z{Lk_?eWD;Egt?y97R6-M(;-TSmH5o?Ng<`VHp8+Su8!+oC*6mtLdl9Lk(%IPV^Gc9 z>J(*NjS!(2#y62tmk)fsR!?E{3qf6Lt0sK0pBCCQerbeb8He}IV2r5Y?rE*F`-7RP zVQYDR+d|4Q`N^4-9s@tAyMvW7o$+Y5oeu9UsKGsS0-XFfF7yE{%6kEVec7(S$0C7d zw**1N`BS48HRR*&=byH1+^)W37ivPy+9kDjl?QZ@^S 4cJ;x*&VHU8z zirH*#2>mP>>_ 3(c$ Xyaybd!#B&pnPEds4$C&!@Db2VJtP9K zADtwr@D*ss@o}GRMOI3M*UA|6)h6rtZX{H$))RJiPgD|0RFvodA(%9YU)cv;d9pBv zQR2!LGxWh9bNK>F-Zo{K%1H8cnCIE;7eQ0&^&?J4GZZaswNKozGG$@d&J`mP_tG2{ zS-}D&rV5QOm~7hB1bLo56v60r;Y4KvoW|gLlW8-KwPWD2EP)A+%2%FMZG81?tIf#O zg9ya=vB!;hj_woABMRCqy|IP2bj&BKKqGN|tLp Sd@EA51fowAl6Q|69QXgV5N zk?oA%Mt??pn16H}7ScO8s=(Jasc+9tT5B#*i6LtruY|z_XS4UhcF|?_l z7a=$z<`u|gN`z?30@>sQ-n|?nvhd*xf5zBG*=0S(8*3Au#I#0P)Rk^IK+2*AV^p35 z-nJ2r{JGe7ZpH*2wwqh#Sg%HXr^$O9h)jdKXE`R%frDiPuYmDxpn`jgslb)!uFpEd zhDY(uLLz=YNd_50T8+Hv)WPTY{HJ20!Jh+{FRki_$;Puw8`;Bm&qkl)k!azjX`Hd; zE>&_!LmG$}91{?qjG#O47hEt1$ij@MTQ-fX<2O|`DTazdO&c@RT37W~8-=dBi}JxU ztjxA ;#p^?F9R>Rao1C!0teuW1{<|2{%#iwtwKq<+_y}}|cf{hC0I zke?4I+1xYI(Wm*@*BYxclo_t9?xJJ^5^_~SM_F{(@6??49A zu%C>|&0fQ0M5O7H#O#b>Hj!=b1vfDKYxP6A-vmux?E`M>$tI0?DVpRC-A!A|InA9w z_typ!S(`tPL@61qo@ `;_h_&02Ohwhf5`{&{wk+ICIOIv9h_N(t3HMb%h7A zJ4-o|477@^?`QFk3w}7fGXi6pIMH$7OM=KO)F;2O;N5 23B6CAHi@}J(_sLXQ_B0+3~_m^s+Mza zU^NXcIe&Ww5>8W}M*Tz79$4kM*M6vu^SW%)MKumi?R@#Z??JKFcBa$BzpEDK Iaa9rr|xOWg?CT^1z68-VxJz>gu{ z0)F9z&NPJj>q~P`-@2Mdk)eRrg2;z6RPrPhQIlr6^G%uMSC+LIT-?`6<&5}z@E7a| zdhR}aMM0A8XzqYzgiKE950&m=1>`hLSnvqAM1I=A@8gVfbsQm{fR+P-6Pw|!Di &QZz^+{CjIZoZ>Kz)rli~#&rgBj8pFU4TE&2IP6 z^hW!H-BxVRhE0qYPeiBi7J5ViDliwW$_f0E6=kIl7I3hx)ml__Z=1Y~-16H8z6|ZU zcZDR78%Zg3reR04UkC%Lt);grUr!-}EgqU5*l<0^@}7x2;)xI6{+SQ(D>h#6iCaQG zdCfk{Ih((muIY2JwrKShiS_G*%O5yc+%`W}wL#Mhn=f9B!hH7YEQ9lKC5<;DA&G!d z?>L36u@c8L(?41( c+hi2XaG9K^T*QJM>`jBI-S)f@PeGQ9vZUaCkk!d_pU0gogOIdP!Ym-Sl25A z%S#PY99RIW&Bzlr&d(`BegU@xqkT^E=8V@?bO~f@fW+SKT2sB^`eIz;00aj>Sg#DI z$b871Z~CE?>E^c>s_FAul>=evv_N|PXd8w Ee@bAd(7#^W_p zlthFaNgs-WZ#4=@Ve0d6_&5)5RqhvlcScvG5OOG_Vw?Nq_%^FewmaX)G%@sqI2oRX zHqTg(jTYZ@tUiX-r=wFLv>0Q$SV?aUm+i=;`023=9=7+u-tTMV?veX-OUaGzG9cC; zMkWm~l=Ah(27gL|MJ_lJZCstidv|7#F5IuZM4pKeEqh@)#VU{BjvvDpnygSlA4s%I zw0=<=d25nRGK=bXyhJ{!IZkN5sCAQ0pQ{V%xi2Al5rTFO24wReO4zAq!f`~nCbM(0 z?1#tSv-6evC4HiD;HGe!KF5=G2-$w7=eB2KNCp=>fL3u48l;( zLa@wJ(Yjy|$prBex9FF|u 4DodkZ`l@7M)>3H@=nh6LN5D5?xC7c@pavsP%`ETP><9iwM~;4- zx0#uD=k)ar;K8eZv@jxD%o6re7NB%UW8>nno?CRKe<0KS`Ts|ys%41<3;%!AV-}u< z`Oq4mNo77}e3wSW&TN7B&yX`^=Cp1QB|UjLgksFKWF`Uah1emi%zzXu>h{s%uU{fn ze*LQTqBThV*3-AdbjzpGh{z_XGv*aV$0>1^7rOL@Zg%kQ#oeNgY+kVAFjfqe{H#XD z3xMSFGx#!zx$q~CI-o?X67OA^r`mMPT!}c(attxoN%ZPfu-*iG)A5aHozuiVCHH*} z=`wjD%U}hbk^`sx&E>+6>hz76f&km7!WQ+!O*vPaqLeI4?BLd44+=#DcLnoEnfv98 z+<->Tcg=)8f8MCOleJ9 _Z 2PBb1FxYFX{yx~v7+2xCXymYsAv`CV5&tXok^&z5aY zhpr|j;d5CAnNidq1HD?wO5t&yn5p6FE#TG$f@dv0&mrP~6P%0K{{5pNtw0YSB7}-L z#i36L?R4ND3l47>3!|vG+}2?A>P`HSY0BL}9R|GXS1slAA{yqP`0fJF%6K^=!^WKO z=Oz&A^26G8#m=5faiz(7@~Gp*I^>G-xwluEyLMC`LKmExk#oN&?Lq{+j{Dc*>fv|Q z?cVtM%;OxH8}Koq9_qp}hhmedG1q6pjClH#7ETdWM&UKlS0cYxW`(A2{iFqsEeK}= zznJ7GW-BKXBCvReS$}kV0^<}YE8)e^x#nlIv`3oBlmlsUUQHr?i++FZzXkQoI0BGP z&C{MEIZZjnkZ dmuc17V8&HgMSG=!N8R`3v4Olk{TgWEr^=WSaHL=YwXlN4(3UEs!u zMlt?-|Bz43!Xb@&*np$u_ch@j6c%FLY4n-7H4SBCDZ1Jk5iSdTp7^8|y-93wbT92i zwDXwGo_b7!U(gA#xRv8b;G)!ah?#I4v! jf zlm?)G@=ZEBf784e`Uw?m0(#j~3$s~yN4lXiAAgsh`nG3R+C1PNZs=hCZ|lY+Bc2hx ztOChB>CxBtw|NZS%yP*}JKh@so&|wopiW>XwHqB}7O&jr;FAX!&zuu@L&hs{u2y$K zdr$NsFra~q51$C %dkaOKYzN$oyK^eNYa`gvxu-%N~p z+&PJy%jKW&+(QDFRBJw8<@Wro6X1x)AHH Y%myR&C>b&XgE1BSN2VDg6^(4WQeAAA3jRB%Xx-ev9hHbB2(F& za9z|?rw 2&)Ud{l+$%4bmuvX50+2kM%W1!s!& 0nqTkDtu= b@W(81XZ@*YWiP zxe0$>Wg?gXW=+LQAJu($6~7X%`;3VuLbcNor787ZkBZr7T{nI07ka;TaLH8e1e?a| zkYGX-HA6%DbHoB8^PziNblU2N8-{t7!63Gk(Yys-TpJ75iy@moY1WYqN237td=?3Ys`=2l5hP~}I1~{OKu%g+E=2jzb-ek=9vssz7Ll;W zo69y??9}b5@ASi%D PQ4!VMxzd+RnW<&cE)SP5=oAauOqQvpj3afe1S>fg@F4tlw{G~Tz(xcZS6 zhz}PVd)3ipz*2Orsa3}+E&CU$%&}fB*9K379rDb~k ;1D+=w7e=l`5p#ru;c$QbD)jL`85>MgX@kHWa&@?5c8LHnGGaI zQ4h_9ZCeJgd=m_W+utdnxCo||lVbb&v86dfD-S{!-%2Zh^NAy)uVsW@ldLZ abhMB*(qf5f8 z2xPm)hf1A|QMn4eSAFx=GHM0S7gmfEFMWOnIJGYQD!pxJXh_9p`b*CtVarp;Ts%&D z3S13%_FnDjhlHO^XS#abpWb|2RhEihDb!Y_4O;WAIrXaa@ACI0WwI|#&gAnzMFeOy z5MMd$iQCzrZy(o+fli!J6u>_J+9kc~um|NpINUn}>;hQW)SO4cuY0?O0=Xh>1IOCV ztNP?}dR3=D1pq6_wq3K>8qt4B6f~>!-XdW?(y+;suC!C O#$gWK!8v}Pe`)+UwnSw_Z^0r&A`s)?(RMJ+;cwV zG{aq(V^=lwB8N@$bVe#c bK?GfyPn`y zYru-~io~%YqUtCXZ1e}=J#`c(f!A#wW^MJxBC{RaIHuy!@@FDU1S_V%J)R-}#D9C! zj3w=kS@~4Ww;MH-u_L}p`9F)modVTa&B|S>=ozlS()nK~z7p>u6M(+$xI6A$ZVC7Q zc1C?%s !<-sd}hlGFs^J5M^zM9&Po#Db^zNpu`mBL2vAl-nV3Gweo zrlFr4>O%?@-A*GE1J8a0#T6Vmf1nIbiPo`5vSMm@SDe!C2 zw-{({I*u7xL+5498F*_qI`KrgG;tnSfE71utnx;&jrqd@ nr_d^7AeWVvy8nQ zJ0Vrsqt9~wZfa(d*rW@0cjIWoM8EiR#U&m=yBgV8SXWfOGP@zm0*G^HpHy-aLR4 z(HxW5qhqUAqVT^5^D2sS_@{J4Lngviz58#D+DAIoh~H~(M3=Io*`7}P8E%Bh4-wp> zri>O5IvYc1$Em3tT86T~tI=hdAgN5o`et?viX~*tw^pC`lJ_RplPPUc8$I+DDCObV zUJ2`FzqI$dhmlN -? nf>`PX6C@AYkXi`F8bqQ>OHRYFls}ZoO3Tb)W;Bx@H*hD5MpE0Zc z73 gdvq?smA2Sb(WV}tM6Axh8D`L-ueh%& frn+glE7sAUQ z$RusjTA04LU>{tBPWrw_R*rkfJ#_7u27WCZNWr7LX8ua__YnOk&=N3F7;Cq+u1oHa z_NBZCwEC?{;h>^yf88AQ%U)?Lnci^;00lq<`CvSt^SQZuF{BO#HuOyOm{%S^8?z&c zD{*y{dN@8!kNptxh$Q1Siox f>L*>~+56CS?Krz1c2k%epd7gb zQD-DQIF%_t!UhHY9DU54Cg;LRw;6A|D=~Ga?kw*niT*^J;B{YpEO8qVslkDnT|lZF zr)Iwf!-4 QUx~|uWiWh zp=AMgjI7CTS)lcCy4rtsU5Ow|kR)B6^y_ONqtph_0imnGE2sh*^b(M-0I}avtR-K6 z>(AT3sOHp(@B3Rz$Hd>;@SN$d7feK
cViCYJ2OS7xHmlt;(ggTPrZOhkLlY?X $#dUMcMHQKg7T|)cj52@7lv3 z?MNl*WbO49EF1cqn>P8JvtrivQoe0Y!9)H#oAU}6A ul+&^+vh{5NkX>wmH^v6_R?Aud>Zx%tXLb8w`M(~40UT& fgM5Pn>L zO8c=+eSxlpii+sMtK&19+ e$LhKjGxi33>*O(lTdQzh>PzvU+BtbUHu zjSU`rJgqSZ#10O$)@m>MGk1Gz9h)$kM$&vgruSES3_KiiyY{%EAz%0?6Cp}Rt>GY0 znYyi-ZdZ07!6!En$^v(nbbf;ob$-blRsz>*R|baU7a^fw)Iq(*ipeI&QT8;f2De^g zY5_A8^JDG)Xe@zWx>W-RP9G#(Tk9DnJbYq|+SEocRR2s7|4kMe+UyQrZvo}7K~LmV z9I)Hikj+%}v7ynWpzesBF%KkFflf_#Vv`^lO;|ERNpT6owPtMDOhMaI8D>d&pKe5q ztKe^>24CAbovntd*Ywih36S4~GN|)Is*NpL7}myz!H&JlL}`GQ!y}9-!>$dK<*7P^ z*7;eyL!qqG2(IG(zYCU+F?XlLq9{F?DUop90jnz#vgs=lOiJgQVL8bgfN!Rb$_hmY z@&2wvwIC2sY9rR2?rQFnUdHs$9S^x+3_jRRGUPh9AUxh~YgU< 3j>9+O z`DaeipzGXeE#S+gIq#uA*{m9sn#AO&fdj~d!h(nF>{Wl|lkw3fES;u94T7|7dKE|A zJ*qE;I3#6HJnM6={<|g;xWYf`RUuxyb3uBnxaQ5e@kMQVCzrQ(0r=3XN5{Lwp +zfMFh_UJ 5Acq3nWAW~V==o>MFQoZOH%S}p9kcez z%g;saG{ ~`hO}wt_;hWpT0AhFnq^Lp4aL2_t^w(k7FHTjWC~#RzY(_s zgY}Mup %FE-X*MWA)WqF(G_&6eu4LRr?;E{ zvID<_nY*b*+O~swk)v)^PUore%kk32UYe4+E-fhzOX~NL4#?7H ;v7o=j!Wvj+fu5I;hI6F=L|>x~${k~b zp)=Jz?ZGI*;QHJ3H;1+)Y}SNa^<`8-*}ujTRez{mFp5wZyULzE uATJ<)HNDk{4bA1M#lAO}L1{-b( z8=(vI-&`@V9r9$&De})Jx$0YAsF`a%TX}~{hLwHWoN?43KF$+t`voMkap9+_**Md9 zw^}ZxZe{Nur4V=fPgvl-?9Zg(ChX6|E6A6+hGJ?ss`7Qssbt-K3%J^;f#wYw?9Mjd z%xbYCAw@jPbat|Fn$F65ag}?E#@-b<`3vY^Sab}#P`F)xf)6!4DcUuiUbQ(dW#ZAH z{7f8rSD`q?6SC=uXsUOuD@>Y4Q@aVrhN#zZ-PbFZRTC&R-@Gn1`(ay(V(y%U_uqS& zTj~NLgo;s45yJ5O@D}Pp3@n$r)$S1V?JMJw=TnbUQyB~D#ky3K)%-YnaP{NN^%hwd z{LZ^1Cs>NIA;@o!I*7}F3B6g7y4he$fIM-as3X$isY5|YmJW3}+WVd{C-fUYY!0!l zR_M^J9Xv+bm{Z^Ug6^G0I~$7i^{#CZnwzNzhaH3RS!rIBD=aW2;=9lwr2m8?PH0Lw zdef0vGr19!gS>Qa5pVp=oJi)=XI(@n !99!wm;iUHo&sR>pq* z1}qc|fxCA*mS6YvT&$ZthO6?Vsk`+5&N3Ezr~-1U*<>xyXwudVlbm`bNeNy*$7n_* zA<4>0dk^L>&r@mLu0B(MY4fX*Wg)1TV!Dul?U};UQqlnl4aig1HAr5&J0%6+9!vL< zV j)!6 z${QwM!Ig=qPbU1q+NHTvM(yGZdth9Wm=kxcj&tW>aE|$ybUnf7c18EaBldSR$-#8e zaeHIKB{;&_i~md`7PbWx7#`odu0AY-2f}gedb{KP53ScEpC)^1`Tuf(`Pts200|0S zP|fu+9LhGiS-TM{G#3f7XNgIJkwBybS)S;_@Kj|-HU@ AUFXw%+SyxF_>7NLol z9b`Y{h^QV?@@!=pCL0@&DE;=WW3kj8R6(S8&_V$dozM(L;dJZ?Xy0!Y=CM$}8e}`> zpZ&jP0^5*8)!LHAac5-BArUHql2kD)hL%0YR2)j!-0~4>cGs9ahIoOTwTLCyN @=BL_Y7JK1`DqA?}g`G;HX-*4s>_sF^G8xNSf*M257%7Lkm zY85W*cr1@x3#yT+4R89{xdC?*&h3cQ2GxNDJV(Erwnb1{D26q23ct^Cp}%~~HIWNL zg@$Z$4_(5W9DitK?)<~=5)cK|?v02JoU~0t(G)RW4BD^fC_)d*o$b&IR0n)htf-5y z4Kc4u?E&ng*Ry{6R?d#yxwt1yCj|>&=Y>$tb&A(KV)PVqcWQclLAQ!lx0E2LjS=~L z^65MJBmgjX^DX1q{n(IlrHpIW@z_7e8!{9q^`rFi^d$6WeX?9NY&LcH8fMO}Q=|1j zDO`Qn4Rd?> <9WyQpYA@ z8sW)(lud-KAr55^W>a>(wt#~l7L2z{Z@~Rudl-zW5q1d5JQi{LJ8%njNe#(Zd~tFJ z*9K16FJcqo4vN^k+&A#*MJ)u#lPA+$9!XQUo=Z^;_Y7Z)(-P=hG8ZQ#VN7K9K8>yz zbwb!0xFu283VL3zrynlHeHIt6m%e%VvHZSA?!GN4tSQfj17`Uy*F}BtS!Lmv&mX`Z zn}nVI_``{+lTK6|Z*BPHfYY{Vgx8!mbao`wV{aMg+wcX}AAXqI97E2l|M94QZjHqG zad-7_xXNzFH{Ow!E}D#ig?nAW6d(>OHy>2KEnS#=f|n^AAtpoH^b}^M1@X{Ibe?__ z+Ol onG`;MX*mX}o!GH$Wy0NrH937deQig;V{= zI%AEND^- U *TgO>eM@u(L; bg5b@Svz=YWpYHN;Z!W}O6@TZ|hv_Le^=l#_uQpTt z=@P9P(DG)h##&~x_o$PQ!=Ei-=4)$?T(E?iZFhB#t+b%$QK(2dA;Le>=?R^)%KMi_ zRlrV|?-plv(k9hY|K@IN`N%Ubn$24x|16ajUGO0&b0uuOlGYpj``!nfAw(7ueer7Z z%WG%$G?yh2g1l3GC}kkmKnR$HgF`c=M44<)qa4sL5VrB)mwcsnshM)CT%>qG(5~Y< zskgmI;g<9icGqQ~@FQxsq%|M*W;6KuJa-{ps3yR>h`uu_TKrvN>P%^NMqu0XII+0g zwbu7B6!ncIDVS8iEm4pTa$xCLH~HchFo~V-tXRkYOR*~vFzFCctH_#Jr>pe zKFu{;^+Gaj7Zz@mfHo(cw!D(uWLt5!8qbtj`WU!kzCb6{JI^;$Mlm!)9{pyDrLYEH zW#(3oiCgR!&;)w$)AOCUmo|=_f1zM8$`CISOG=T^(1pW^Th&@fq%zs@Gpyv}x)2f* zczPHzQoI*OUw3(0&bn3h#%uLAC-QwBVatPHi7Qc`&l1XKbYA;mb#(wZwpksdzw83} zaw $Dan=(4?atL@F2$$Y1<{x|A(O(;kiA$qKTV)c_&>PCd5 z7}n{VKm|W-)A~-{xUc`)8}W)5tL2POf!mm}Ro=5Q0lVY7)liJ+ngbKbi?xNX9Bl^* z)OjGQpN#j^wvIYf4j&&N=AJ2Eza%=v^7i?MlhsomSLG~nO3|U+tb7YZx*R=5M7_zj zyMgOuWqXQ Z^)sud^mRfn^W;b9CTa=s_$DU5R+N7gZ0MzKWL&ig{ zdj_9R96s{Ylj=w__gRQaIX+RJ7RD`YIfZTj5|7R*o8F%I)JND|bdC(`k==uiZT3(t zxad@C@3h=pK!#k6>OvVRj(#@)3sWA-amVA0NFi6Iap$={Wc`8+fLWb1`}e@C(i|DF z4$IX;eL`h0X~N<>6A$^iX2Gm6gV3yUT@36ltF> Ku@{oL~2off1%gw0-Qi_UGC4;{<9+htAwOX)ClD(Ne8&NJDt&>4V&MOV0|K9@8ht zW)*)2UgdjRfu+CvL!nF(%6Z0 FbL-}Hv(WxL?8g!kM{R;?p(P@soIk$l0?=#t9Bs<*Ifa`41X4n1i4Qi^G74D{kp z(sFFoDsn94Gmbf3#GWWA?R1Lcml0e7xwN}^pcn%IP~9v3vAfT~`M^Vr1e4TZ4?}Xv zTQ^ 4-wC$`t)F^-vl{yu7>*gUH^k;vZa_A*x<%&eDtp- zXsi=P?U|#q+= Xz8zpn&UN#3N*rJ#4Io1z1&Lq|ji z#!k1lP9t#}2;$fZt$53rOe{c89=~3BG^CSQa1n@3@Y7&U`Mgfn*l#s&2(T*>WLfV_ zOfz&ve4nN~TNXk=?|8(=kSd8I^|zK#B{OLCAb*D1$@^bhUu_ync;6JJiqUbM$Wxvu z+!t>Ku#s o~0jxudVT|>nfSgM>NzAu6Yst+0NcD r#LHM$_Xq#D(OBGVF zkJ9-i&3)YmPQHQ?dy*x&JkbHWHM{iren=Za^y5<4eCAsq0p=xMF{M}RTpF$QFnUWc ze|@Jn>yU03Jyogly>W8Y+bOi$umN1w25#5kcF*1G+=hs)SdRc@SMXgi3D)2{Je1TB zrc_6R!F^k`abnR0E@KQqFO&|yD-@CJcu!Fh(#v*A_>(&KqLHt#wx-HvV|Nk?>h|9e zpBlUk8BMQIlE#dKY_951rAWK7lXe4S*;e6 `g72Ufv={H!^BKBPJDXWgq_dUIQC`h*4V>8cZI6O+7OcM=S zk*vl93rQcu&?eM~5~3dCrN1xM{u!eY7I#|D1U<;fitrz@DyP`@C7eV==(SZX|FlvA z%}}m+YBa$j^=r7U 6N$i;YtK4k;{+Q6}B&& z+^~^fCRrJKvBO#b_zsE2f}_hwD-|u(-#0najGt0x@y08maNCnY;F(ohRz8c-o0RZg zkizj+=sn-j1>)&~=<6q&P%g5t`y*L;)IMcprKkmbKMiU8cJC=6Z`?NcpdYKxctFe| za9DPyPsb+?sYsHQC~-TB*WNYzTQZJT{~OmHgCYt9jrJKA^%=X|gPWZ5gRB$WA)C{4 zm(&DFJ!hxDWh$IOYO0079 e563<-p|hkSwOt0yO1DgL_tV!-?cKBB)FZ$ly@1O z&V7eG$FHG4p4;M^ffFOA`26-E#3wkw6BK7qA@whzP%%ZhPc$xCk~!?WK6#$aUY_1~ z&hBF5KFO^x=mhHPH^T9Mmh1mnNHfay?>WpviBRMxCC;nESUtP=e-5ZH)^r0GjJSQ` zkfY<(mzcJ9_cav$+hgo=7u*b#TEymHJI5 =UWxpM^bv9S*v lMAGU!QV?cm$M^6& z>zZ;xTh$?GBHra$u5p3#%2#RLCmofa>j3n{d3yf%nL57%*Dl-Uu|u_0Spl|Fo>BBU zT`n}I#*vWCOfsKFp57EqvL{r$@X)INbS89vP$JDZ0W1{qzY`41tQ$V4=yuBGEq;+5 zIWztXVxc2 bae}f VAZesT1c!@sT3~vtXd<42KT=3Fo+98`jG=x zi&D2WO47%}Q}!epj5r*EZEYvdv3POPA<}0*?^VAr?M+`{!;&22nhPv(k{ToK!$k6_ z7{tb&E2PZ(7D-FJGv<0!AoV$r+Fe7Biql!*Cmtr8Zvg)Go)V1~;#zAk@;d|ldEaQL zp9Zub0xHXN^WHiA4pvee-|p(fQ6 hGqVM|^F0 #bZ5 z8psJ?+jqFiW7~>k`Jg;ArO`S5&~B4Ue15Ov2Z5(qBRs|OMW(|UL~tF&(rJrqPj3I^ z*#EsK3ZGx ^c?rFuwY?>@@f9Gk)HaxS zSclT8ARoTbIn%HKQo*F(INgSUtzqOqatba=WrGg6Z1vc2XOi=oC)bfww#wL{>z7%3 z|8>(5KMda WL-d|Lah-k`w^52o73z`ue<;?02PQ)=;XZ245|&3|BL!& zbL8sTfnPuqpiKQ|csGoC^kypIO6zT6-N!BDRsMZ9?JvObft$Hk_IDBA$Z?Kzt_yvG z2uTeaAl~H5?M~JInAL{|vHLrU*K`g&29bo<*TmZ3V+Dw5TaJPNO+mIE4P(Do%QG*; zn|NIjum4uY-F@zQM*Fr6x7N%IlSuO2Cyi)la_T7$ZspZx2aS+x0Wa=!b{Ai&Wrszq zAyfvYeNS@gn;Oj}{Mu)AC^^J1;#M0zgPKVu1ec#z1P$5yv);8N$TQPEiNCUslUT`Z zb2Hp u#i1$dkQ&g zS3>su_5wIUYGFjxqq99JA90PmPLA9+%?01>4qEz%@3-K|!Vk3zY5ix)8n98p`P)SG z^HAV$S4Ac%Du*v5$DLH={me=ZixJB|yZ{^xEzO=SrX>?0-GCMQmScrZ_!#vIQ{#3! z4Iapm@HTZee% 5l?C{YACf?CuR1PXyqKI7`TtA}?;Yml`*|7_|S0E@BGU~9XA z6^5g<<;|XzbrduXf_%)HObl}rbj-MWpYQ0?u)U`hy{iU_vv=8NJNgjL%$K(WaoOb> z^$*f8p?MV|UBc1Fn~I=ebgO%lX4u|GtGN)nrKgkf=kPT%`aPqhH(U(r%_$C!X6 zKmrP{KR?rqn;0ChVA|rT)S7BK1PEK0(@qvIsyjsL>&~`EglxjD#>I~a)Jc3=^fKJW zzQ6@*Hq}o)i@sFO$M{F&GUXiO9W-YBaKN%LV1PogNj5a1->t8WEqZFPFtmP?0XHKJ zA?vUp<=ih21E^;199u_uY(v0?F@i#8?pw>HH(cu$j#eVU!j`m&0J=;_SCAmQ9GTc= z{N~!gjSzrPM9{FKA9>M{Rbv&CN-{lNP(CPd9%|r1ilT3i*k`XeX^|%WJ|U?iJ{}6% z%@7*#=&4=CllW_G&%?N+Kao3IeaI0Q$!L{xDRnqj%O&j9GPgfL7%$h0^U)auHn4*e zZygG1z$~_}Noy`;e~;*{ainG*s#SmU8EAmANVw8xA`i9qT9apTPH_*7A3z$+P4`fr zGBEx^m;PuCzm9PVPH9vd_Ou$cugc5Q3uDdsf-6u4J5rD(>Ju0)k^adof *N^3PvIkofUZkCvcm*qf$)N2NSZeDZJmCnmw$#(>eh= zoP`=`J?b2ra=N-m5gZHL9p_W*_E>i}x5OAcvKnRdOvFNEf1sC#RoTZfB883~k^b#} zy|pNYR(tXG (XLENc)G0XSIcV||d+8&pc