From 337a8fa8fa623f7b8d439e25895d4e56ed98392b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Kr=C3=BCger?= Date: Mon, 6 Jul 2020 10:10:21 +0200 Subject: [PATCH] Initial commit --- .gitignore | 83 + LICENSE.md | 21 + Podfile | 11 + Podfile.lock | 21 + README.md | 4 + caffeine.xcodeproj/project.pbxproj | 844 ++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/xcschemes/caffeine.xcscheme | 98 + .../xcschemes/caffeineUITests.xcscheme | 71 + caffeine.xcworkspace/contents.xcworkspacedata | 10 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + caffeine/AppDelegate.swift | 101 + .../AppIcon.appiconset/1024upscale.png | Bin 0 -> 103345 bytes .../AppIcon.appiconset/29@2x.png | Bin 0 -> 1104 bytes .../AppIcon.appiconset/29@3x.png | Bin 0 -> 1483 bytes .../AppIcon.appiconset/40@2x.png | Bin 0 -> 1422 bytes .../AppIcon.appiconset/40@3x.png | Bin 0 -> 1979 bytes .../AppIcon.appiconset/60@2x.png | Bin 0 -> 1979 bytes .../AppIcon.appiconset/60@3x.png | Bin 0 -> 2872 bytes .../AppIcon.appiconset/Contents.json | 60 + caffeine/Assets.xcassets/Contents.json | 6 + caffeine/Assets.xcassets/Input/Contents.json | 6 + .../Assets.xcassets/Input/Cups/Contents.json | 6 + .../Cups/cupLarge.imageset/Contents.json | 21 + .../Input/Cups/cupLarge.imageset/cupLarge.pdf | Bin 0 -> 4116 bytes .../Cups/cupMiddle.imageset/Contents.json | 21 + .../Cups/cupMiddle.imageset/cupMiddle.pdf | Bin 0 -> 4116 bytes .../Cups/cupSmall.imageset/Contents.json | 21 + .../Input/Cups/cupSmall.imageset/cupSmall.pdf | Bin 0 -> 4115 bytes .../Assets.xcassets/Input/Milk/Contents.json | 6 + .../Milk/milkBottleCow.imageset/Contents.json | 21 + .../milkBottleCow.imageset/milkBottleCow.pdf | Bin 0 -> 5136 bytes .../Contents.json | 21 + .../milkBottleLactoseFree.pdf | Bin 0 -> 16387 bytes .../Milk/milkBottleSoy.imageset/Contents.json | 21 + .../milkBottleSoy.imageset/milkBottleSoy.pdf | Bin 0 -> 4705 bytes .../Input/Shots/1-shot.imageset/Contents.json | 21 + .../Input/Shots/1-shot.imageset/oneshot.pdf | Bin 0 -> 4063 bytes .../Input/Shots/2-shots.imageset/2-shots.pdf | Bin 0 -> 4104 bytes .../Shots/2-shots.imageset/Contents.json | 21 + .../Input/Shots/3-shots.imageset/3-shots.pdf | Bin 0 -> 4169 bytes .../Shots/3-shots.imageset/Contents.json | 21 + .../Assets.xcassets/Input/Shots/Contents.json | 6 + .../Input/Sugar/1-sugar.imageset/1-sugar.pdf | Bin 0 -> 4034 bytes .../Sugar/1-sugar.imageset/Contents.json | 21 + .../Sugar/2-sugars.imageset/2-sugars.pdf | Bin 0 -> 4200 bytes .../Sugar/2-sugars.imageset/Contents.json | 21 + .../Sugar/3-sugars.imageset/3-sugars.pdf | Bin 0 -> 4349 bytes .../Sugar/3-sugars.imageset/Contents.json | 21 + .../Assets.xcassets/Input/Sugar/Contents.json | 6 + .../Quick Launch/Contents.json | 6 + .../quickLarge.imageset/Contents.json | 21 + .../quickLarge.imageset/quickLarge.png | Bin 0 -> 2174 bytes .../quickLargePressed.imageset/Contents.json | 21 + .../quickLargePressed.png | Bin 0 -> 2183 bytes .../quickMedium.imageset/Contents.json | 21 + .../quickMedium.imageset/quickMedium.png | Bin 0 -> 1870 bytes .../quickMediumPressed.imageset/Contents.json | 21 + .../quickMediumPressed.png | Bin 0 -> 1897 bytes .../quickShot.imageset/Contents.json | 21 + .../quickShot.imageset/QuickShot.png | Bin 0 -> 1684 bytes .../quickShotPressed.imageset/Contents.json | 21 + .../quickShotPressed.png | Bin 0 -> 1724 bytes .../quickSmall.imageset/Contents.json | 21 + .../quickSmall.imageset/quickSmall.png | Bin 0 -> 1823 bytes .../quickSmallPressed.imageset/Contents.json | 21 + .../quickSmallPressed.png | Bin 0 -> 1862 bytes caffeine/Assets.xcassets/TabBar/Contents.json | 6 + .../TabBar/consumption.imageset/Contents.json | 23 + .../consumption.imageset/consumption@1x.png | Bin 0 -> 3237 bytes .../consumption.imageset/conumption@2x.png | Bin 0 -> 3774 bytes .../consumption.imageset/conumption@3x.png | Bin 0 -> 4303 bytes .../TabBar/input.imageset/Contents.json | 23 + .../TabBar/input.imageset/input@1x.png | Bin 0 -> 3094 bytes .../TabBar/input.imageset/input@2x.png | Bin 0 -> 3447 bytes .../TabBar/input.imageset/input@3x.png | Bin 0 -> 3820 bytes .../TabBar/settings.imageset/Contents.json | 23 + .../TabBar/settings.imageset/settings@1x.png | Bin 0 -> 3381 bytes .../TabBar/settings.imageset/settings@2x.png | Bin 0 -> 4156 bytes .../TabBar/settings.imageset/settings@3x.png | Bin 0 -> 4849 bytes .../TabBar/statistics.imageset/Contents.json | 23 + .../statistics.imageset/statistics@1x.png | Bin 0 -> 3201 bytes .../statistics.imageset/statistics@2x.png | Bin 0 -> 3730 bytes .../statistics.imageset/statistics@3x.png | Bin 0 -> 4230 bytes caffeine/Assets.xcassets/Total/Contents.json | 6 + .../totalCupsIcon.imageset/Contents.json | 21 + .../totalCupsIcon.imageset/totalCupsIcon.pdf | Bin 0 -> 4977 bytes .../totalMilkIcon.imageset/Contents.json | 21 + .../totalMilkIcon.imageset/totalMilkIcon.pdf | Bin 0 -> 4330 bytes .../totalSugarIcon.imageset/Contents.json | 21 + .../totalSugarIcon.pdf | Bin 0 -> 4239 bytes .../disclosure.imageset/Contents.json | 23 + .../disclosure.imageset/disclosure.png | Bin 0 -> 145 bytes .../disclosure.imageset/disclosure@2x.png | Bin 0 -> 181 bytes .../disclosure.imageset/disclosure@3x.png | Bin 0 -> 243 bytes .../launchIcon.imageset/Contents.json | 23 + .../launchIcon.imageset/launch.png | Bin 0 -> 1691 bytes .../launchIcon.imageset/launch@2x.png | Bin 0 -> 3327 bytes .../launchIcon.imageset/launch@3x.png | Bin 0 -> 4929 bytes .../selectIcon-green.imageset/Contents.json | 21 + .../selectIcon-green.pdf | Bin 0 -> 4052 bytes .../vektor.imageset/Contents.json | 23 + .../vektor.imageset/vektor@1x.png | Bin 0 -> 3007 bytes .../vektor.imageset/vektor@2x.png | Bin 0 -> 3131 bytes .../vektor.imageset/vektor@3x.png | Bin 0 -> 3358 bytes caffeine/Base.lproj/LaunchScreen.storyboard | 54 + caffeine/Base.lproj/Main.storyboard | 3981 +++++++++++++++++ caffeine/Data/Consumable.swift | 137 + caffeine/Data/ConsumableProperties.swift | 149 + caffeine/Data/PeriodicConsumption.swift | 110 + caffeine/Data/UserSettings.swift | 129 + caffeine/Info.plist | 39 + .../Consumption.xcdatamodel/contents | 13 + .../ConsumptionDataProvider.swift | 14 + .../ConsumptionStore/ConsumptionStore.swift | 187 + .../ConsumptionStore/ContextProvider.swift | 65 + .../ConsumptionStore/DatastoreProvider.swift | 47 + .../ConsumptionStore/PersistenceService.swift | 61 + caffeine/Services/DrinksDataService.swift | 34 + caffeine/Services/DrinksService.swift | 41 + .../HealthKit/CaffeineDataService.swift | 187 + .../HealthKit/HealthStoreService.swift | 152 + caffeine/Styling/CaffeineColors.swift | 66 + .../Base.lproj/Localizable.strings | 79 + .../CaffeineDataDescription.rtf | 21 + .../Supporting Files/Consumption/Coffee.plist | 110 + .../Supporting Files/Consumption/Milk.plist | 110 + .../Supporting Files/Consumption/Size.plist | 30 + .../Supporting Files/Consumption/Sugar.plist | 110 + .../MindModellDesctiption.rtf | 44 + .../de.lproj/Localizable.strings | 79 + .../UICaffeineConsumptionRecentButton.swift | 73 + caffeine/View/UICaffeineInputButton.swift | 51 + caffeine/View/UICaffeineInputButtonView.swift | 23 + caffeine/View/UICaffeineInputOKButton.swift | 50 + caffeine/View/UICaffeineSlider.swift | 30 + .../View/UICaffeineStatisticsChartView.swift | 243 + ...UICaffeineStatisticsTimeSelectorView.swift | 59 + caffeine/View/UISliderPopupView.swift | 10 + .../ConsumptionViewController.swift | 83 + .../ViewController/InputViewController.swift | 200 + .../SettingsViewController.swift | 162 + .../StatisticsViewController.swift | 165 + caffeine/caffeine.entitlements | 10 + caffeine/de.lproj/LaunchScreen.strings | 1 + caffeine/de.lproj/Main.strings | 198 + caffeineUITests/Info.plist | 22 + caffeineUITests/caffeineUITests.swift | 90 + fastlane/Fastfile | 18 + fastlane/README.md | 34 + fastlane/Snapfile | 29 + fastlane/SnapshotHelper.swift | 279 ++ fastlane/screenshots/Framefile.json | 44 + fastlane/screenshots/background.jpg | Bin 0 -> 19826 bytes fastlane/screenshots/de-DE/title.strings | 9 + fastlane/screenshots/en-US/title.strings | 9 + fastlane/screenshots/screenshots.html | 598 +++ swiftlint.yml | 68 + 158 files changed, 10665 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE.md create mode 100644 Podfile create mode 100644 Podfile.lock create mode 100644 README.md create mode 100644 caffeine.xcodeproj/project.pbxproj create mode 100644 caffeine.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 caffeine.xcodeproj/xcshareddata/xcschemes/caffeine.xcscheme create mode 100644 caffeine.xcodeproj/xcshareddata/xcschemes/caffeineUITests.xcscheme create mode 100644 caffeine.xcworkspace/contents.xcworkspacedata create mode 100644 caffeine.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 caffeine/AppDelegate.swift create mode 100644 caffeine/Assets.xcassets/AppIcon.appiconset/1024upscale.png create mode 100644 caffeine/Assets.xcassets/AppIcon.appiconset/29@2x.png create mode 100644 caffeine/Assets.xcassets/AppIcon.appiconset/29@3x.png create mode 100644 caffeine/Assets.xcassets/AppIcon.appiconset/40@2x.png create mode 100644 caffeine/Assets.xcassets/AppIcon.appiconset/40@3x.png create mode 100644 caffeine/Assets.xcassets/AppIcon.appiconset/60@2x.png create mode 100644 caffeine/Assets.xcassets/AppIcon.appiconset/60@3x.png create mode 100644 caffeine/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 caffeine/Assets.xcassets/Contents.json create mode 100644 caffeine/Assets.xcassets/Input/Contents.json create mode 100644 caffeine/Assets.xcassets/Input/Cups/Contents.json create mode 100644 caffeine/Assets.xcassets/Input/Cups/cupLarge.imageset/Contents.json create mode 100644 caffeine/Assets.xcassets/Input/Cups/cupLarge.imageset/cupLarge.pdf create mode 100644 caffeine/Assets.xcassets/Input/Cups/cupMiddle.imageset/Contents.json create mode 100644 caffeine/Assets.xcassets/Input/Cups/cupMiddle.imageset/cupMiddle.pdf create mode 100644 caffeine/Assets.xcassets/Input/Cups/cupSmall.imageset/Contents.json create mode 100644 caffeine/Assets.xcassets/Input/Cups/cupSmall.imageset/cupSmall.pdf create mode 100644 caffeine/Assets.xcassets/Input/Milk/Contents.json create mode 100644 caffeine/Assets.xcassets/Input/Milk/milkBottleCow.imageset/Contents.json create mode 100644 caffeine/Assets.xcassets/Input/Milk/milkBottleCow.imageset/milkBottleCow.pdf create mode 100644 caffeine/Assets.xcassets/Input/Milk/milkBottleLactoseFree.imageset/Contents.json create mode 100644 caffeine/Assets.xcassets/Input/Milk/milkBottleLactoseFree.imageset/milkBottleLactoseFree.pdf create mode 100644 caffeine/Assets.xcassets/Input/Milk/milkBottleSoy.imageset/Contents.json create mode 100644 caffeine/Assets.xcassets/Input/Milk/milkBottleSoy.imageset/milkBottleSoy.pdf create mode 100644 caffeine/Assets.xcassets/Input/Shots/1-shot.imageset/Contents.json create mode 100644 caffeine/Assets.xcassets/Input/Shots/1-shot.imageset/oneshot.pdf create mode 100644 caffeine/Assets.xcassets/Input/Shots/2-shots.imageset/2-shots.pdf create mode 100644 caffeine/Assets.xcassets/Input/Shots/2-shots.imageset/Contents.json create mode 100644 caffeine/Assets.xcassets/Input/Shots/3-shots.imageset/3-shots.pdf create mode 100644 caffeine/Assets.xcassets/Input/Shots/3-shots.imageset/Contents.json create mode 100644 caffeine/Assets.xcassets/Input/Shots/Contents.json create mode 100644 caffeine/Assets.xcassets/Input/Sugar/1-sugar.imageset/1-sugar.pdf create mode 100644 caffeine/Assets.xcassets/Input/Sugar/1-sugar.imageset/Contents.json create mode 100644 caffeine/Assets.xcassets/Input/Sugar/2-sugars.imageset/2-sugars.pdf create mode 100644 caffeine/Assets.xcassets/Input/Sugar/2-sugars.imageset/Contents.json create mode 100644 caffeine/Assets.xcassets/Input/Sugar/3-sugars.imageset/3-sugars.pdf create mode 100644 caffeine/Assets.xcassets/Input/Sugar/3-sugars.imageset/Contents.json create mode 100644 caffeine/Assets.xcassets/Input/Sugar/Contents.json create mode 100644 caffeine/Assets.xcassets/Quick Launch/Contents.json create mode 100644 caffeine/Assets.xcassets/Quick Launch/quickLarge.imageset/Contents.json create mode 100644 caffeine/Assets.xcassets/Quick Launch/quickLarge.imageset/quickLarge.png create mode 100644 caffeine/Assets.xcassets/Quick Launch/quickLargePressed.imageset/Contents.json create mode 100644 caffeine/Assets.xcassets/Quick Launch/quickLargePressed.imageset/quickLargePressed.png create mode 100644 caffeine/Assets.xcassets/Quick Launch/quickMedium.imageset/Contents.json create mode 100644 caffeine/Assets.xcassets/Quick Launch/quickMedium.imageset/quickMedium.png create mode 100644 caffeine/Assets.xcassets/Quick Launch/quickMediumPressed.imageset/Contents.json create mode 100644 caffeine/Assets.xcassets/Quick Launch/quickMediumPressed.imageset/quickMediumPressed.png create mode 100644 caffeine/Assets.xcassets/Quick Launch/quickShot.imageset/Contents.json create mode 100644 caffeine/Assets.xcassets/Quick Launch/quickShot.imageset/QuickShot.png create mode 100644 caffeine/Assets.xcassets/Quick Launch/quickShotPressed.imageset/Contents.json create mode 100644 caffeine/Assets.xcassets/Quick Launch/quickShotPressed.imageset/quickShotPressed.png create mode 100644 caffeine/Assets.xcassets/Quick Launch/quickSmall.imageset/Contents.json create mode 100644 caffeine/Assets.xcassets/Quick Launch/quickSmall.imageset/quickSmall.png create mode 100644 caffeine/Assets.xcassets/Quick Launch/quickSmallPressed.imageset/Contents.json create mode 100644 caffeine/Assets.xcassets/Quick Launch/quickSmallPressed.imageset/quickSmallPressed.png create mode 100644 caffeine/Assets.xcassets/TabBar/Contents.json create mode 100644 caffeine/Assets.xcassets/TabBar/consumption.imageset/Contents.json create mode 100644 caffeine/Assets.xcassets/TabBar/consumption.imageset/consumption@1x.png create mode 100644 caffeine/Assets.xcassets/TabBar/consumption.imageset/conumption@2x.png create mode 100644 caffeine/Assets.xcassets/TabBar/consumption.imageset/conumption@3x.png create mode 100644 caffeine/Assets.xcassets/TabBar/input.imageset/Contents.json create mode 100644 caffeine/Assets.xcassets/TabBar/input.imageset/input@1x.png create mode 100644 caffeine/Assets.xcassets/TabBar/input.imageset/input@2x.png create mode 100644 caffeine/Assets.xcassets/TabBar/input.imageset/input@3x.png create mode 100644 caffeine/Assets.xcassets/TabBar/settings.imageset/Contents.json create mode 100644 caffeine/Assets.xcassets/TabBar/settings.imageset/settings@1x.png create mode 100644 caffeine/Assets.xcassets/TabBar/settings.imageset/settings@2x.png create mode 100644 caffeine/Assets.xcassets/TabBar/settings.imageset/settings@3x.png create mode 100644 caffeine/Assets.xcassets/TabBar/statistics.imageset/Contents.json create mode 100644 caffeine/Assets.xcassets/TabBar/statistics.imageset/statistics@1x.png create mode 100644 caffeine/Assets.xcassets/TabBar/statistics.imageset/statistics@2x.png create mode 100644 caffeine/Assets.xcassets/TabBar/statistics.imageset/statistics@3x.png create mode 100644 caffeine/Assets.xcassets/Total/Contents.json create mode 100644 caffeine/Assets.xcassets/Total/totalCupsIcon.imageset/Contents.json create mode 100644 caffeine/Assets.xcassets/Total/totalCupsIcon.imageset/totalCupsIcon.pdf create mode 100644 caffeine/Assets.xcassets/Total/totalMilkIcon.imageset/Contents.json create mode 100644 caffeine/Assets.xcassets/Total/totalMilkIcon.imageset/totalMilkIcon.pdf create mode 100644 caffeine/Assets.xcassets/Total/totalSugarIcon.imageset/Contents.json create mode 100644 caffeine/Assets.xcassets/Total/totalSugarIcon.imageset/totalSugarIcon.pdf create mode 100644 caffeine/Assets.xcassets/disclosure.imageset/Contents.json create mode 100644 caffeine/Assets.xcassets/disclosure.imageset/disclosure.png create mode 100644 caffeine/Assets.xcassets/disclosure.imageset/disclosure@2x.png create mode 100644 caffeine/Assets.xcassets/disclosure.imageset/disclosure@3x.png create mode 100644 caffeine/Assets.xcassets/launchIcon.imageset/Contents.json create mode 100644 caffeine/Assets.xcassets/launchIcon.imageset/launch.png create mode 100644 caffeine/Assets.xcassets/launchIcon.imageset/launch@2x.png create mode 100644 caffeine/Assets.xcassets/launchIcon.imageset/launch@3x.png create mode 100644 caffeine/Assets.xcassets/selectIcon-green.imageset/Contents.json create mode 100644 caffeine/Assets.xcassets/selectIcon-green.imageset/selectIcon-green.pdf create mode 100644 caffeine/Assets.xcassets/vektor.imageset/Contents.json create mode 100644 caffeine/Assets.xcassets/vektor.imageset/vektor@1x.png create mode 100644 caffeine/Assets.xcassets/vektor.imageset/vektor@2x.png create mode 100644 caffeine/Assets.xcassets/vektor.imageset/vektor@3x.png create mode 100644 caffeine/Base.lproj/LaunchScreen.storyboard create mode 100644 caffeine/Base.lproj/Main.storyboard create mode 100644 caffeine/Data/Consumable.swift create mode 100644 caffeine/Data/ConsumableProperties.swift create mode 100644 caffeine/Data/PeriodicConsumption.swift create mode 100644 caffeine/Data/UserSettings.swift create mode 100644 caffeine/Info.plist create mode 100644 caffeine/Services/ConsumptionStore/Consumption.xcdatamodeld/Consumption.xcdatamodel/contents create mode 100644 caffeine/Services/ConsumptionStore/ConsumptionDataProvider.swift create mode 100644 caffeine/Services/ConsumptionStore/ConsumptionStore.swift create mode 100644 caffeine/Services/ConsumptionStore/ContextProvider.swift create mode 100644 caffeine/Services/ConsumptionStore/DatastoreProvider.swift create mode 100644 caffeine/Services/ConsumptionStore/PersistenceService.swift create mode 100644 caffeine/Services/DrinksDataService.swift create mode 100644 caffeine/Services/DrinksService.swift create mode 100644 caffeine/Services/HealthKit/CaffeineDataService.swift create mode 100644 caffeine/Services/HealthKit/HealthStoreService.swift create mode 100644 caffeine/Styling/CaffeineColors.swift create mode 100644 caffeine/Supporting Files/Base.lproj/Localizable.strings create mode 100644 caffeine/Supporting Files/CaffeineDataDescription.rtf create mode 100644 caffeine/Supporting Files/Consumption/Coffee.plist create mode 100644 caffeine/Supporting Files/Consumption/Milk.plist create mode 100644 caffeine/Supporting Files/Consumption/Size.plist create mode 100644 caffeine/Supporting Files/Consumption/Sugar.plist create mode 100644 caffeine/Supporting Files/MindModellDesctiption.rtf create mode 100644 caffeine/Supporting Files/de.lproj/Localizable.strings create mode 100644 caffeine/View/UICaffeineConsumptionRecentButton.swift create mode 100644 caffeine/View/UICaffeineInputButton.swift create mode 100644 caffeine/View/UICaffeineInputButtonView.swift create mode 100644 caffeine/View/UICaffeineInputOKButton.swift create mode 100644 caffeine/View/UICaffeineSlider.swift create mode 100644 caffeine/View/UICaffeineStatisticsChartView.swift create mode 100644 caffeine/View/UICaffeineStatisticsTimeSelectorView.swift create mode 100644 caffeine/View/UISliderPopupView.swift create mode 100644 caffeine/ViewController/ConsumptionViewController.swift create mode 100644 caffeine/ViewController/InputViewController.swift create mode 100644 caffeine/ViewController/SettingsViewController.swift create mode 100644 caffeine/ViewController/StatisticsViewController.swift create mode 100644 caffeine/caffeine.entitlements create mode 100644 caffeine/de.lproj/LaunchScreen.strings create mode 100644 caffeine/de.lproj/Main.strings create mode 100644 caffeineUITests/Info.plist create mode 100644 caffeineUITests/caffeineUITests.swift create mode 100644 fastlane/Fastfile create mode 100644 fastlane/README.md create mode 100644 fastlane/Snapfile create mode 100644 fastlane/SnapshotHelper.swift create mode 100644 fastlane/screenshots/Framefile.json create mode 100644 fastlane/screenshots/background.jpg create mode 100644 fastlane/screenshots/de-DE/title.strings create mode 100644 fastlane/screenshots/en-US/title.strings create mode 100644 fastlane/screenshots/screenshots.html create mode 100644 swiftlint.yml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..569d9dd --- /dev/null +++ b/.gitignore @@ -0,0 +1,83 @@ +# Xcode +# +# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore + +## Build generated +build/ +DerivedData/ + +## Various settings +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +xcuserdata/ +.DS_Store + +## Other +*.moved-aside +*.xccheckout +*.xcscmblueprint + +## Obj-C/Swift specific +*.hmap +*.ipa +*.dSYM.zip +*.dSYM + +## Playgrounds +timeline.xctimeline +playground.xcworkspace + +# Swift Package Manager +# +# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. +# Packages/ +# Package.pins +# Package.resolved +.build/ + +# CocoaPods +# +# We recommend against adding the Pods directory to your .gitignore. However +# you should judge for yourself, the pros and cons are mentioned at: +# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control +# +Pods/ +# +# Add this line if you want to avoid checking in source code from the Xcode workspace +# *.xcworkspace + +# Carthage +# +# Add this line if you want to avoid checking in source code from Carthage dependencies. +# Carthage/Checkouts + +Carthage/Build + +# Accio dependency management +Dependencies/ +.accio/ + +# fastlane +# +# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the +# screenshots whenever they are needed. +# For more information about the recommended setup visit: +# https://docs.fastlane.tools/best-practices/source-control/#source-control + +fastlane/report.xml +fastlane/Preview.html +fastlane/screenshots/**/*.png +fastlane/test_output + +# Code Injection +# +# After new code Injection tools there's a generated folder /iOSInjectionProject +# https://github.com/johnno1962/injectionforxcode + +iOSInjectionProject/ diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..4854fb8 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 Simon Christian Krüger + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Podfile b/Podfile new file mode 100644 index 0000000..8223f0b --- /dev/null +++ b/Podfile @@ -0,0 +1,11 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '9.0' + +target 'caffeine' do + # Comment this line if you're not using Swift and don't want to use dynamic frameworks + use_frameworks! + + # Pods for caffeine + inherit! :search_paths + pod 'Spring', :git => 'https://github.com/MengTo/Spring.git' +end diff --git a/Podfile.lock b/Podfile.lock new file mode 100644 index 0000000..9ddee44 --- /dev/null +++ b/Podfile.lock @@ -0,0 +1,21 @@ +PODS: + - Spring (1.0.6) + +DEPENDENCIES: + - Spring (from `https://github.com/MengTo/Spring.git`) + +EXTERNAL SOURCES: + Spring: + :git: https://github.com/MengTo/Spring.git + +CHECKOUT OPTIONS: + Spring: + :commit: 50d92a5b9e08848387ae95bf44c6ad20834f7083 + :git: https://github.com/MengTo/Spring.git + +SPEC CHECKSUMS: + Spring: 3d113f14575ef79aec9c5f906dfa4f5001c03254 + +PODFILE CHECKSUM: 02db9cfd46bb75d696ea5fcf5ba1b997cc110895 + +COCOAPODS: 1.9.3 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7a85d0e --- /dev/null +++ b/README.md @@ -0,0 +1,4 @@ +# caffe:ne +The project of this app is one of my first publications on the Apple AppStore in 2015. When I closed my account in 2017 the code was forgotten and the project was left in the bottom shelf of my drawer. With corona knocking on our door I finally found the time to read through my old code and refactor it a bit. It's far from perfect and lacks a clean architectural concept though it was always dear to me. Therefore I felt obliged to get an AppStore account again and publish it for free. At the same time I would like others to learn from my mistakes. Therefore the whole codebase is open source. + +Depending on my availability I will maybe publish some additional updates here and on the AppStore. diff --git a/caffeine.xcodeproj/project.pbxproj b/caffeine.xcodeproj/project.pbxproj new file mode 100644 index 0000000..dea6c69 --- /dev/null +++ b/caffeine.xcodeproj/project.pbxproj @@ -0,0 +1,844 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 600647DA1BAE0A0E00101295 /* Coffee.plist in Resources */ = {isa = PBXBuildFile; fileRef = 600647D91BAE0A0E00101295 /* Coffee.plist */; }; + 600647DC1BAE0A1B00101295 /* Milk.plist in Resources */ = {isa = PBXBuildFile; fileRef = 600647DB1BAE0A1B00101295 /* Milk.plist */; }; + 600647DE1BAE0A2700101295 /* Sugar.plist in Resources */ = {isa = PBXBuildFile; fileRef = 600647DD1BAE0A2700101295 /* Sugar.plist */; }; + 600647E01BAE0A3D00101295 /* Size.plist in Resources */ = {isa = PBXBuildFile; fileRef = 600647DF1BAE0A3D00101295 /* Size.plist */; }; + 600D1C381BE7C47C00DC9500 /* UICaffeineInputButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 600D1C371BE7C47C00DC9500 /* UICaffeineInputButtonView.swift */; }; + 601336D11BF389E6006A67D3 /* UICaffeineStatisticsTimeSelectorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 601336D01BF389E6006A67D3 /* UICaffeineStatisticsTimeSelectorView.swift */; }; + 601EB15A1C00CF9A00F56A2A /* UICaffeineConsumptionRecentButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 601EB1591C00CF9A00F56A2A /* UICaffeineConsumptionRecentButton.swift */; }; + 601FAA291BAC52D200553555 /* InputViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 601FAA271BAC52D200553555 /* InputViewController.swift */; }; + 601FAA2A1BAC52D200553555 /* ConsumptionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 601FAA281BAC52D200553555 /* ConsumptionViewController.swift */; }; + 601FAA2C1BAC52E300553555 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 601FAA2B1BAC52E300553555 /* AppDelegate.swift */; }; + 602E64B21BAC1BDF00E25D52 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 602E64B01BAC1BDF00E25D52 /* Main.storyboard */; }; + 602E64B41BAC1BDF00E25D52 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 602E64B31BAC1BDF00E25D52 /* Assets.xcassets */; }; + 602E64B71BAC1BDF00E25D52 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 602E64B51BAC1BDF00E25D52 /* LaunchScreen.storyboard */; }; + 602E64E51BAC3C6C00E25D52 /* HealthKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 602E64E41BAC3C6C00E25D52 /* HealthKit.framework */; }; + 603DEE0424AB7C640079A79C /* HealthStoreService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 603DEE0324AB7C640079A79C /* HealthStoreService.swift */; }; + 603DEE0924AB7FE10079A79C /* swiftlint.yml in Resources */ = {isa = PBXBuildFile; fileRef = 603DEE0824AB7FE00079A79C /* swiftlint.yml */; }; + 603DEE0D24AB87030079A79C /* UserSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 603DEE0C24AB87030079A79C /* UserSettings.swift */; }; + 60481E1624AB71D8008DE168 /* CaffeineColors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60481E1524AB71D8008DE168 /* CaffeineColors.swift */; }; + 60481E1924AB76C8008DE168 /* Consumable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60481E1824AB76C8008DE168 /* Consumable.swift */; }; + 60481E1B24AB7860008DE168 /* ConsumableProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60481E1A24AB7860008DE168 /* ConsumableProperties.swift */; }; + 60496F2B1BD011CA00A72757 /* UISliderPopupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60496F2A1BD011CA00A72757 /* UISliderPopupView.swift */; }; + 60496F2D1BD015CE00A72757 /* UICaffeineSlider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60496F2C1BD015CE00A72757 /* UICaffeineSlider.swift */; }; + 6062DFF11BDAA05E003EF136 /* UICaffeineInputButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6062DFF01BDAA05E003EF136 /* UICaffeineInputButton.swift */; }; + 60BE64AE24AF620D000F26C4 /* caffeineUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60BE64AD24AF620D000F26C4 /* caffeineUITests.swift */; }; + 60BE64B624AF634E000F26C4 /* SnapshotHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60BE64B524AF634E000F26C4 /* SnapshotHelper.swift */; }; + 60CA813D24AC6D8200DDED35 /* PeriodicConsumption.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60CA813C24AC6D8200DDED35 /* PeriodicConsumption.swift */; }; + 60CA813F24AC781100DDED35 /* CaffeineDataService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60CA813E24AC781100DDED35 /* CaffeineDataService.swift */; }; + 60CA814124ADC04800DDED35 /* DrinksService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60CA814024ADC04800DDED35 /* DrinksService.swift */; }; + 60CA814624ADC39D00DDED35 /* Consumption.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 60CA814424ADC39D00DDED35 /* Consumption.xcdatamodeld */; }; + 60CA814824ADC45500DDED35 /* PersistenceService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60CA814724ADC45500DDED35 /* PersistenceService.swift */; }; + 60CA814A24ADC48B00DDED35 /* DatastoreProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60CA814924ADC48B00DDED35 /* DatastoreProvider.swift */; }; + 60CA814C24ADC4A700DDED35 /* ContextProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60CA814B24ADC4A700DDED35 /* ContextProvider.swift */; }; + 60CA814E24ADC57500DDED35 /* ConsumptionStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60CA814D24ADC57500DDED35 /* ConsumptionStore.swift */; }; + 60CA815024ADC59B00DDED35 /* ConsumptionDataProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60CA814F24ADC59B00DDED35 /* ConsumptionDataProvider.swift */; }; + 60D3BAF41BC12CC100CAC7DE /* StatisticsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60D3BAF31BC12CC100CAC7DE /* StatisticsViewController.swift */; }; + 60D3BAF61BC12D2000CAC7DE /* SettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60D3BAF51BC12D2000CAC7DE /* SettingsViewController.swift */; }; + 60E25B911C03418D007205C3 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 60E25B931C03418D007205C3 /* Localizable.strings */; }; + 60E76D2B1BEA183300670CEA /* UICaffeineInputOKButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60E76D2A1BEA183300670CEA /* UICaffeineInputOKButton.swift */; }; + 60E76D2D1BEB608800670CEA /* UICaffeineStatisticsChartView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60E76D2C1BEB608800670CEA /* UICaffeineStatisticsChartView.swift */; }; + 95B669E5BD1E01661467093F /* Pods_caffeine.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AC0D4BC68B85877491EC9915 /* Pods_caffeine.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 60BE64B024AF620D000F26C4 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 602E649F1BAC1BDF00E25D52 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 602E64A61BAC1BDF00E25D52; + remoteInfo = caffeine; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 41D1ABB40FE4971EAEC727F3 /* Pods-caffeineUITests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-caffeineUITests.release.xcconfig"; path = "Pods/Target Support Files/Pods-caffeineUITests/Pods-caffeineUITests.release.xcconfig"; sourceTree = ""; }; + 59916642B9BECC76E54897AF /* Pods-caffeineUITests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-caffeineUITests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-caffeineUITests/Pods-caffeineUITests.debug.xcconfig"; sourceTree = ""; }; + 600647D91BAE0A0E00101295 /* Coffee.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Coffee.plist; path = "Supporting Files/Consumption/Coffee.plist"; sourceTree = ""; }; + 600647DB1BAE0A1B00101295 /* Milk.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Milk.plist; path = "Supporting Files/Consumption/Milk.plist"; sourceTree = ""; }; + 600647DD1BAE0A2700101295 /* Sugar.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Sugar.plist; path = "Supporting Files/Consumption/Sugar.plist"; sourceTree = ""; }; + 600647DF1BAE0A3D00101295 /* Size.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Size.plist; path = "Supporting Files/Consumption/Size.plist"; sourceTree = ""; }; + 600D1C371BE7C47C00DC9500 /* UICaffeineInputButtonView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = UICaffeineInputButtonView.swift; path = View/UICaffeineInputButtonView.swift; sourceTree = ""; }; + 601336D01BF389E6006A67D3 /* UICaffeineStatisticsTimeSelectorView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = UICaffeineStatisticsTimeSelectorView.swift; path = View/UICaffeineStatisticsTimeSelectorView.swift; sourceTree = ""; }; + 601EB1591C00CF9A00F56A2A /* UICaffeineConsumptionRecentButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = UICaffeineConsumptionRecentButton.swift; path = View/UICaffeineConsumptionRecentButton.swift; sourceTree = ""; }; + 601FAA271BAC52D200553555 /* InputViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = InputViewController.swift; path = ViewController/InputViewController.swift; sourceTree = ""; }; + 601FAA281BAC52D200553555 /* ConsumptionViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ConsumptionViewController.swift; path = ViewController/ConsumptionViewController.swift; sourceTree = ""; }; + 601FAA2B1BAC52E300553555 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 602E64A71BAC1BDF00E25D52 /* caffeine.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = caffeine.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 602E64B11BAC1BDF00E25D52 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 602E64B31BAC1BDF00E25D52 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 602E64B61BAC1BDF00E25D52 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 602E64B81BAC1BDF00E25D52 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 602E64E41BAC3C6C00E25D52 /* HealthKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = HealthKit.framework; path = System/Library/Frameworks/HealthKit.framework; sourceTree = SDKROOT; }; + 602E64E61BAC3C6C00E25D52 /* caffeine.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = caffeine.entitlements; sourceTree = ""; }; + 603DEE0324AB7C640079A79C /* HealthStoreService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HealthStoreService.swift; sourceTree = ""; }; + 603DEE0824AB7FE00079A79C /* swiftlint.yml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.yaml; path = swiftlint.yml; sourceTree = SOURCE_ROOT; }; + 603DEE0C24AB87030079A79C /* UserSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSettings.swift; sourceTree = ""; }; + 60481E1524AB71D8008DE168 /* CaffeineColors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CaffeineColors.swift; sourceTree = ""; }; + 60481E1824AB76C8008DE168 /* Consumable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Consumable.swift; sourceTree = ""; }; + 60481E1A24AB7860008DE168 /* ConsumableProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConsumableProperties.swift; sourceTree = ""; }; + 60496F2A1BD011CA00A72757 /* UISliderPopupView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = UISliderPopupView.swift; path = View/UISliderPopupView.swift; sourceTree = ""; }; + 60496F2C1BD015CE00A72757 /* UICaffeineSlider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = UICaffeineSlider.swift; path = View/UICaffeineSlider.swift; sourceTree = ""; }; + 6062DFF01BDAA05E003EF136 /* UICaffeineInputButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = UICaffeineInputButton.swift; path = View/UICaffeineInputButton.swift; sourceTree = ""; }; + 60BE64AB24AF620D000F26C4 /* caffeineUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = caffeineUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 60BE64AD24AF620D000F26C4 /* caffeineUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = caffeineUITests.swift; sourceTree = ""; }; + 60BE64AF24AF620D000F26C4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 60BE64B524AF634E000F26C4 /* SnapshotHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SnapshotHelper.swift; path = fastlane/SnapshotHelper.swift; sourceTree = SOURCE_ROOT; }; + 60CA813C24AC6D8200DDED35 /* PeriodicConsumption.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PeriodicConsumption.swift; sourceTree = ""; }; + 60CA813E24AC781100DDED35 /* CaffeineDataService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CaffeineDataService.swift; sourceTree = ""; }; + 60CA814024ADC04800DDED35 /* DrinksService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DrinksService.swift; sourceTree = ""; }; + 60CA814524ADC39D00DDED35 /* Consumption.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = Consumption.xcdatamodel; sourceTree = ""; }; + 60CA814724ADC45500DDED35 /* PersistenceService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PersistenceService.swift; sourceTree = ""; }; + 60CA814924ADC48B00DDED35 /* DatastoreProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DatastoreProvider.swift; sourceTree = ""; }; + 60CA814B24ADC4A700DDED35 /* ContextProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContextProvider.swift; sourceTree = ""; }; + 60CA814D24ADC57500DDED35 /* ConsumptionStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConsumptionStore.swift; sourceTree = ""; }; + 60CA814F24ADC59B00DDED35 /* ConsumptionDataProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConsumptionDataProvider.swift; sourceTree = ""; }; + 60D3BAF31BC12CC100CAC7DE /* StatisticsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = StatisticsViewController.swift; path = ViewController/StatisticsViewController.swift; sourceTree = ""; }; + 60D3BAF51BC12D2000CAC7DE /* SettingsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SettingsViewController.swift; path = ViewController/SettingsViewController.swift; sourceTree = ""; }; + 60D941701BC8623100C203C6 /* MindModellDesctiption.rtf */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.rtf; name = MindModellDesctiption.rtf; path = "Supporting Files/MindModellDesctiption.rtf"; sourceTree = ""; }; + 60D941721BC8659C00C203C6 /* CaffeineDataDescription.rtf */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.rtf; name = CaffeineDataDescription.rtf; path = "Supporting Files/CaffeineDataDescription.rtf"; sourceTree = ""; }; + 60E25B921C03418D007205C3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/Localizable.strings; sourceTree = ""; }; + 60E25B941C048E19007205C3 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Main.strings; sourceTree = ""; }; + 60E25B951C048E19007205C3 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/LaunchScreen.strings; sourceTree = ""; }; + 60E25B961C048E19007205C3 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = ""; }; + 60E76D2A1BEA183300670CEA /* UICaffeineInputOKButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = UICaffeineInputOKButton.swift; path = View/UICaffeineInputOKButton.swift; sourceTree = ""; }; + 60E76D2C1BEB608800670CEA /* UICaffeineStatisticsChartView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = UICaffeineStatisticsChartView.swift; path = View/UICaffeineStatisticsChartView.swift; sourceTree = ""; }; + 6943F8CA7228E6BA43EF1D52 /* Pods-caffeine.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-caffeine.release.xcconfig"; path = "Pods/Target Support Files/Pods-caffeine/Pods-caffeine.release.xcconfig"; sourceTree = ""; }; + 6A7D83803EA44D18A8ACA433 /* Pods-caffeineTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-caffeineTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-caffeineTests/Pods-caffeineTests.debug.xcconfig"; sourceTree = ""; }; + 6B0FA68D033FC175428005D5 /* Pods-caffeineTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-caffeineTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-caffeineTests/Pods-caffeineTests.release.xcconfig"; sourceTree = ""; }; + 805C0FA2158610E631948B9C /* libPods-caffeineTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-caffeineTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + AC0D4BC68B85877491EC9915 /* Pods_caffeine.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_caffeine.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + BA3B96DF380F91729B1B1847 /* Pods.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + D62277E8878BF98CB27A8302 /* libPods-caffeineUITests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-caffeineUITests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + DE4BBE3566B0763A7FAAAF50 /* Pods-caffeine.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-caffeine.debug.xcconfig"; path = "Pods/Target Support Files/Pods-caffeine/Pods-caffeine.debug.xcconfig"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 602E64A41BAC1BDF00E25D52 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 602E64E51BAC3C6C00E25D52 /* HealthKit.framework in Frameworks */, + 95B669E5BD1E01661467093F /* Pods_caffeine.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 60BE64A824AF620D000F26C4 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 600647D81BAE09CD00101295 /* Consumption */ = { + isa = PBXGroup; + children = ( + 600647D91BAE0A0E00101295 /* Coffee.plist */, + 600647DB1BAE0A1B00101295 /* Milk.plist */, + 600647DD1BAE0A2700101295 /* Sugar.plist */, + 600647DF1BAE0A3D00101295 /* Size.plist */, + ); + name = Consumption; + sourceTree = ""; + }; + 601FAA2D1BAC532300553555 /* View */ = { + isa = PBXGroup; + children = ( + 60496F2A1BD011CA00A72757 /* UISliderPopupView.swift */, + 60496F2C1BD015CE00A72757 /* UICaffeineSlider.swift */, + 601EB1591C00CF9A00F56A2A /* UICaffeineConsumptionRecentButton.swift */, + 6062DFF01BDAA05E003EF136 /* UICaffeineInputButton.swift */, + 60E76D2A1BEA183300670CEA /* UICaffeineInputOKButton.swift */, + 600D1C371BE7C47C00DC9500 /* UICaffeineInputButtonView.swift */, + 60E76D2C1BEB608800670CEA /* UICaffeineStatisticsChartView.swift */, + 601336D01BF389E6006A67D3 /* UICaffeineStatisticsTimeSelectorView.swift */, + ); + name = View; + sourceTree = ""; + }; + 602E649E1BAC1BDF00E25D52 = { + isa = PBXGroup; + children = ( + 602E64A91BAC1BDF00E25D52 /* caffeine */, + 60BE64AC24AF620D000F26C4 /* caffeineUITests */, + 658C97C1AE0B060543CE9128 /* Frameworks */, + 602E64A81BAC1BDF00E25D52 /* Products */, + 94E80EB2AEC9C94EF41E466C /* Pods */, + ); + sourceTree = ""; + }; + 602E64A81BAC1BDF00E25D52 /* Products */ = { + isa = PBXGroup; + children = ( + 602E64A71BAC1BDF00E25D52 /* caffeine.app */, + 60BE64AB24AF620D000F26C4 /* caffeineUITests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 602E64A91BAC1BDF00E25D52 /* caffeine */ = { + isa = PBXGroup; + children = ( + 601FAA2B1BAC52E300553555 /* AppDelegate.swift */, + 60481E1724AB76A5008DE168 /* Data */, + 60481E1424AB71BE008DE168 /* Styling */, + 603DEE0224AB7C2D0079A79C /* Services */, + 601FAA2D1BAC532300553555 /* View */, + 602E64DB1BAC1BF400E25D52 /* ViewController */, + 602E64DD1BAC1C0600E25D52 /* Supporting Files */, + ); + path = caffeine; + sourceTree = ""; + }; + 602E64DB1BAC1BF400E25D52 /* ViewController */ = { + isa = PBXGroup; + children = ( + 601FAA281BAC52D200553555 /* ConsumptionViewController.swift */, + 601FAA271BAC52D200553555 /* InputViewController.swift */, + 60D3BAF31BC12CC100CAC7DE /* StatisticsViewController.swift */, + 60D3BAF51BC12D2000CAC7DE /* SettingsViewController.swift */, + ); + name = ViewController; + sourceTree = ""; + }; + 602E64DC1BAC1BFC00E25D52 /* Storyboards */ = { + isa = PBXGroup; + children = ( + 602E64B01BAC1BDF00E25D52 /* Main.storyboard */, + 602E64B51BAC1BDF00E25D52 /* LaunchScreen.storyboard */, + ); + name = Storyboards; + sourceTree = ""; + }; + 602E64DD1BAC1C0600E25D52 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 600647D81BAE09CD00101295 /* Consumption */, + 602E64DC1BAC1BFC00E25D52 /* Storyboards */, + 602E64B31BAC1BDF00E25D52 /* Assets.xcassets */, + 602E64E61BAC3C6C00E25D52 /* caffeine.entitlements */, + 60E25B931C03418D007205C3 /* Localizable.strings */, + 60D941701BC8623100C203C6 /* MindModellDesctiption.rtf */, + 60D941721BC8659C00C203C6 /* CaffeineDataDescription.rtf */, + 602E64B81BAC1BDF00E25D52 /* Info.plist */, + 603DEE0824AB7FE00079A79C /* swiftlint.yml */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 603DEE0224AB7C2D0079A79C /* Services */ = { + isa = PBXGroup; + children = ( + 60CA814324ADC38400DDED35 /* ConsumptionStore */, + 60CA815324ADC83700DDED35 /* HealthKit */, + 60CA814024ADC04800DDED35 /* DrinksService.swift */, + ); + path = Services; + sourceTree = ""; + }; + 60481E1424AB71BE008DE168 /* Styling */ = { + isa = PBXGroup; + children = ( + 60481E1524AB71D8008DE168 /* CaffeineColors.swift */, + ); + path = Styling; + sourceTree = ""; + }; + 60481E1724AB76A5008DE168 /* Data */ = { + isa = PBXGroup; + children = ( + 60481E1824AB76C8008DE168 /* Consumable.swift */, + 60481E1A24AB7860008DE168 /* ConsumableProperties.swift */, + 60CA813C24AC6D8200DDED35 /* PeriodicConsumption.swift */, + 603DEE0C24AB87030079A79C /* UserSettings.swift */, + ); + path = Data; + sourceTree = ""; + }; + 60BE64AC24AF620D000F26C4 /* caffeineUITests */ = { + isa = PBXGroup; + children = ( + 60BE64AD24AF620D000F26C4 /* caffeineUITests.swift */, + 60BE64B524AF634E000F26C4 /* SnapshotHelper.swift */, + 60BE64AF24AF620D000F26C4 /* Info.plist */, + ); + path = caffeineUITests; + sourceTree = ""; + }; + 60CA814324ADC38400DDED35 /* ConsumptionStore */ = { + isa = PBXGroup; + children = ( + 60CA814424ADC39D00DDED35 /* Consumption.xcdatamodeld */, + 60CA814F24ADC59B00DDED35 /* ConsumptionDataProvider.swift */, + 60CA814D24ADC57500DDED35 /* ConsumptionStore.swift */, + 60CA814724ADC45500DDED35 /* PersistenceService.swift */, + 60CA814924ADC48B00DDED35 /* DatastoreProvider.swift */, + 60CA814B24ADC4A700DDED35 /* ContextProvider.swift */, + ); + path = ConsumptionStore; + sourceTree = ""; + }; + 60CA815324ADC83700DDED35 /* HealthKit */ = { + isa = PBXGroup; + children = ( + 60CA813E24AC781100DDED35 /* CaffeineDataService.swift */, + 603DEE0324AB7C640079A79C /* HealthStoreService.swift */, + ); + path = HealthKit; + sourceTree = ""; + }; + 658C97C1AE0B060543CE9128 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 602E64E41BAC3C6C00E25D52 /* HealthKit.framework */, + BA3B96DF380F91729B1B1847 /* Pods.framework */, + AC0D4BC68B85877491EC9915 /* Pods_caffeine.framework */, + 805C0FA2158610E631948B9C /* libPods-caffeineTests.a */, + D62277E8878BF98CB27A8302 /* libPods-caffeineUITests.a */, + ); + name = Frameworks; + sourceTree = ""; + }; + 94E80EB2AEC9C94EF41E466C /* Pods */ = { + isa = PBXGroup; + children = ( + DE4BBE3566B0763A7FAAAF50 /* Pods-caffeine.debug.xcconfig */, + 6943F8CA7228E6BA43EF1D52 /* Pods-caffeine.release.xcconfig */, + 6A7D83803EA44D18A8ACA433 /* Pods-caffeineTests.debug.xcconfig */, + 6B0FA68D033FC175428005D5 /* Pods-caffeineTests.release.xcconfig */, + 59916642B9BECC76E54897AF /* Pods-caffeineUITests.debug.xcconfig */, + 41D1ABB40FE4971EAEC727F3 /* Pods-caffeineUITests.release.xcconfig */, + ); + name = Pods; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 602E64A61BAC1BDF00E25D52 /* caffeine */ = { + isa = PBXNativeTarget; + buildConfigurationList = 602E64D11BAC1BDF00E25D52 /* Build configuration list for PBXNativeTarget "caffeine" */; + buildPhases = ( + A4AE9D0B6EDC84E5FC899167 /* [CP] Check Pods Manifest.lock */, + 603DEE0524AB7F700079A79C /* Swiftlint */, + 602E64A31BAC1BDF00E25D52 /* Sources */, + 602E64A41BAC1BDF00E25D52 /* Frameworks */, + 602E64A51BAC1BDF00E25D52 /* Resources */, + B931EF7F89DA3D474234C581 /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = caffeine; + productName = caffeine; + productReference = 602E64A71BAC1BDF00E25D52 /* caffeine.app */; + productType = "com.apple.product-type.application"; + }; + 60BE64AA24AF620D000F26C4 /* caffeineUITests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 60BE64B424AF620D000F26C4 /* Build configuration list for PBXNativeTarget "caffeineUITests" */; + buildPhases = ( + 60BE64A724AF620D000F26C4 /* Sources */, + 60BE64A824AF620D000F26C4 /* Frameworks */, + 60BE64A924AF620D000F26C4 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 60BE64B124AF620D000F26C4 /* PBXTargetDependency */, + ); + name = caffeineUITests; + productName = caffeineUITests; + productReference = 60BE64AB24AF620D000F26C4 /* caffeineUITests.xctest */; + productType = "com.apple.product-type.bundle.ui-testing"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 602E649F1BAC1BDF00E25D52 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 1150; + LastUpgradeCheck = 1150; + ORGANIZATIONNAME = kayos; + TargetAttributes = { + 602E64A61BAC1BDF00E25D52 = { + CreatedOnToolsVersion = 7.0; + DevelopmentTeam = T2MU43SWN2; + LastSwiftMigration = 0800; + ProvisioningStyle = Manual; + SystemCapabilities = { + com.apple.ApplicationGroups.iOS = { + enabled = 1; + }; + com.apple.BackgroundModes = { + enabled = 0; + }; + com.apple.HealthKit = { + enabled = 1; + }; + }; + }; + 60BE64AA24AF620D000F26C4 = { + CreatedOnToolsVersion = 11.5; + DevelopmentTeam = C5HCUYE57C; + ProvisioningStyle = Automatic; + TestTargetID = 602E64A61BAC1BDF00E25D52; + }; + }; + }; + buildConfigurationList = 602E64A21BAC1BDF00E25D52 /* Build configuration list for PBXProject "caffeine" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + de, + ); + mainGroup = 602E649E1BAC1BDF00E25D52; + productRefGroup = 602E64A81BAC1BDF00E25D52 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 602E64A61BAC1BDF00E25D52 /* caffeine */, + 60BE64AA24AF620D000F26C4 /* caffeineUITests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 602E64A51BAC1BDF00E25D52 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 602E64B71BAC1BDF00E25D52 /* LaunchScreen.storyboard in Resources */, + 600647E01BAE0A3D00101295 /* Size.plist in Resources */, + 602E64B41BAC1BDF00E25D52 /* Assets.xcassets in Resources */, + 600647DA1BAE0A0E00101295 /* Coffee.plist in Resources */, + 603DEE0924AB7FE10079A79C /* swiftlint.yml in Resources */, + 602E64B21BAC1BDF00E25D52 /* Main.storyboard in Resources */, + 60E25B911C03418D007205C3 /* Localizable.strings in Resources */, + 600647DC1BAE0A1B00101295 /* Milk.plist in Resources */, + 600647DE1BAE0A2700101295 /* Sugar.plist in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 60BE64A924AF620D000F26C4 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 603DEE0524AB7F700079A79C /* Swiftlint */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = Swiftlint; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "if [ -x \"$(command -v swiftlint)\" ]; then\n swiftlint autocorrect --config swiftlint.yml\n #swiftlint --config swiftlint.yml\n echo \"Hello world\"\nelse\n echo \"An error occured. Swiftlint should be installed.\"\n exit 1\nfi\n\n"; + }; + A4AE9D0B6EDC84E5FC899167 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-caffeine-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + B931EF7F89DA3D474234C581 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-caffeine/Pods-caffeine-frameworks.sh", + "${BUILT_PRODUCTS_DIR}/Spring/Spring.framework", + ); + name = "[CP] Embed Pods Frameworks"; + outputPaths = ( + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Spring.framework", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-caffeine/Pods-caffeine-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 602E64A31BAC1BDF00E25D52 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 60CA814824ADC45500DDED35 /* PersistenceService.swift in Sources */, + 60CA813F24AC781100DDED35 /* CaffeineDataService.swift in Sources */, + 600D1C381BE7C47C00DC9500 /* UICaffeineInputButtonView.swift in Sources */, + 60CA814C24ADC4A700DDED35 /* ContextProvider.swift in Sources */, + 603DEE0D24AB87030079A79C /* UserSettings.swift in Sources */, + 601EB15A1C00CF9A00F56A2A /* UICaffeineConsumptionRecentButton.swift in Sources */, + 601FAA2C1BAC52E300553555 /* AppDelegate.swift in Sources */, + 6062DFF11BDAA05E003EF136 /* UICaffeineInputButton.swift in Sources */, + 603DEE0424AB7C640079A79C /* HealthStoreService.swift in Sources */, + 60CA815024ADC59B00DDED35 /* ConsumptionDataProvider.swift in Sources */, + 60CA814E24ADC57500DDED35 /* ConsumptionStore.swift in Sources */, + 60CA814A24ADC48B00DDED35 /* DatastoreProvider.swift in Sources */, + 60CA814624ADC39D00DDED35 /* Consumption.xcdatamodeld in Sources */, + 60E76D2B1BEA183300670CEA /* UICaffeineInputOKButton.swift in Sources */, + 601FAA2A1BAC52D200553555 /* ConsumptionViewController.swift in Sources */, + 601FAA291BAC52D200553555 /* InputViewController.swift in Sources */, + 60481E1624AB71D8008DE168 /* CaffeineColors.swift in Sources */, + 601336D11BF389E6006A67D3 /* UICaffeineStatisticsTimeSelectorView.swift in Sources */, + 60496F2D1BD015CE00A72757 /* UICaffeineSlider.swift in Sources */, + 60D3BAF41BC12CC100CAC7DE /* StatisticsViewController.swift in Sources */, + 60481E1924AB76C8008DE168 /* Consumable.swift in Sources */, + 60CA814124ADC04800DDED35 /* DrinksService.swift in Sources */, + 60496F2B1BD011CA00A72757 /* UISliderPopupView.swift in Sources */, + 60481E1B24AB7860008DE168 /* ConsumableProperties.swift in Sources */, + 60D3BAF61BC12D2000CAC7DE /* SettingsViewController.swift in Sources */, + 60CA813D24AC6D8200DDED35 /* PeriodicConsumption.swift in Sources */, + 60E76D2D1BEB608800670CEA /* UICaffeineStatisticsChartView.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 60BE64A724AF620D000F26C4 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 60BE64AE24AF620D000F26C4 /* caffeineUITests.swift in Sources */, + 60BE64B624AF634E000F26C4 /* SnapshotHelper.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 60BE64B124AF620D000F26C4 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 602E64A61BAC1BDF00E25D52 /* caffeine */; + targetProxy = 60BE64B024AF620D000F26C4 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 602E64B01BAC1BDF00E25D52 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 602E64B11BAC1BDF00E25D52 /* Base */, + 60E25B941C048E19007205C3 /* de */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 602E64B51BAC1BDF00E25D52 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 602E64B61BAC1BDF00E25D52 /* Base */, + 60E25B951C048E19007205C3 /* de */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; + 60E25B931C03418D007205C3 /* Localizable.strings */ = { + isa = PBXVariantGroup; + children = ( + 60E25B921C03418D007205C3 /* Base */, + 60E25B961C048E19007205C3 /* de */, + ); + name = Localizable.strings; + path = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 602E64CF1BAC1BDF00E25D52 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/**"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.5; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 602E64D01BAC1BDF00E25D52 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/**"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.5; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 5.0; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 602E64D21BAC1BDF00E25D52 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = DE4BBE3566B0763A7FAAAF50 /* Pods-caffeine.debug.xcconfig */; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_ENTITLEMENTS = caffeine/caffeine.entitlements; + CODE_SIGN_IDENTITY = "Apple Distribution: Simon Krüger (T2MU43SWN2)"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Distribution: Simon Krüger (T2MU43SWN2)"; + CODE_SIGN_STYLE = Manual; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEVELOPMENT_TEAM = T2MU43SWN2; + FRAMEWORK_SEARCH_PATHS = "$(inherited)/**"; + INFOPLIST_FILE = caffeine/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 13.5; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + MARKETING_VERSION = 1.1.0; + PRODUCT_BUNDLE_IDENTIFIER = org.cr0ss.caffeine; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE = ""; + PROVISIONING_PROFILE_SPECIFIER = "Caffeine AppStore"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 602E64D31BAC1BDF00E25D52 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 6943F8CA7228E6BA43EF1D52 /* Pods-caffeine.release.xcconfig */; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_ENTITLEMENTS = caffeine/caffeine.entitlements; + CODE_SIGN_IDENTITY = "Apple Distribution: Simon Krüger (T2MU43SWN2)"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Distribution: Simon Krüger (T2MU43SWN2)"; + CODE_SIGN_STYLE = Manual; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = T2MU43SWN2; + FRAMEWORK_SEARCH_PATHS = "$(inherited)/**"; + INFOPLIST_FILE = caffeine/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 13.5; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + MARKETING_VERSION = 1.1.0; + PRODUCT_BUNDLE_IDENTIFIER = org.cr0ss.caffeine; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE = ""; + PROVISIONING_PROFILE_SPECIFIER = "Caffeine AppStore"; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 60BE64B224AF620D000F26C4 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = C5HCUYE57C; + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = caffeineUITests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = org.cr0ss.caffeineUITests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_TARGET_NAME = caffeine; + }; + name = Debug; + }; + 60BE64B324AF620D000F26C4 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = C5HCUYE57C; + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = caffeineUITests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = org.cr0ss.caffeineUITests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_TARGET_NAME = caffeine; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 602E64A21BAC1BDF00E25D52 /* Build configuration list for PBXProject "caffeine" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 602E64CF1BAC1BDF00E25D52 /* Debug */, + 602E64D01BAC1BDF00E25D52 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 602E64D11BAC1BDF00E25D52 /* Build configuration list for PBXNativeTarget "caffeine" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 602E64D21BAC1BDF00E25D52 /* Debug */, + 602E64D31BAC1BDF00E25D52 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 60BE64B424AF620D000F26C4 /* Build configuration list for PBXNativeTarget "caffeineUITests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 60BE64B224AF620D000F26C4 /* Debug */, + 60BE64B324AF620D000F26C4 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + +/* Begin XCVersionGroup section */ + 60CA814424ADC39D00DDED35 /* Consumption.xcdatamodeld */ = { + isa = XCVersionGroup; + children = ( + 60CA814524ADC39D00DDED35 /* Consumption.xcdatamodel */, + ); + currentVersion = 60CA814524ADC39D00DDED35 /* Consumption.xcdatamodel */; + path = Consumption.xcdatamodeld; + sourceTree = ""; + versionGroupType = wrapper.xcdatamodel; + }; +/* End XCVersionGroup section */ + }; + rootObject = 602E649F1BAC1BDF00E25D52 /* Project object */; +} diff --git a/caffeine.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/caffeine.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..c935d83 --- /dev/null +++ b/caffeine.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/caffeine.xcodeproj/xcshareddata/xcschemes/caffeine.xcscheme b/caffeine.xcodeproj/xcshareddata/xcschemes/caffeine.xcscheme new file mode 100644 index 0000000..fd43f23 --- /dev/null +++ b/caffeine.xcodeproj/xcshareddata/xcschemes/caffeine.xcscheme @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/caffeine.xcodeproj/xcshareddata/xcschemes/caffeineUITests.xcscheme b/caffeine.xcodeproj/xcshareddata/xcschemes/caffeineUITests.xcscheme new file mode 100644 index 0000000..3b2907a --- /dev/null +++ b/caffeine.xcodeproj/xcshareddata/xcschemes/caffeineUITests.xcscheme @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/caffeine.xcworkspace/contents.xcworkspacedata b/caffeine.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..0786a33 --- /dev/null +++ b/caffeine.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/caffeine.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/caffeine.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/caffeine.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/caffeine/AppDelegate.swift b/caffeine/AppDelegate.swift new file mode 100644 index 0000000..e2705fc --- /dev/null +++ b/caffeine/AppDelegate.swift @@ -0,0 +1,101 @@ +import UIKit + +// Statistics Setup +internal let intersectDistance: [Int] = [4, 1, 5, 61] +internal let catmullRomSelection: [Bool] = [true, false, true, false] + +enum ShortcutItem: String { + case first = "caffeine.shortcut.first" + case second = "caffeine.shortcut.second" + case third = "caffeine.shortcut.third" + + var consumable: Consumable { + let recentDrinks = DrinksService.shared.getRecentDrinks() + switch self { + case .first: + return recentDrinks[0] + case .second: + return recentDrinks[1] + case .third: + return recentDrinks[2] + } + } + + var shortcutItem: UIMutableApplicationShortcutItem? { + return .init( + type: self.rawValue, + localizedTitle: consumable.coffee.localizedTitle, + localizedSubtitle: "\(consumable.milk.localizedTitle), \(consumable.sugar.localizedTitle)", + icon: UIApplicationShortcutIcon(templateImageName: consumable.size.imageName), + userInfo: [:] as [String: NSSecureCoding] + ) + } +} + +// MARK: Begin AppDelegate +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + + internal var window: UIWindow? + + /// A storage provider to be accessed by core data relevant classes. + lazy internal var datastoreProvider: DatastoreProvider = { + return DatastoreProvider() + }() + + /// A context provider to be accessed by core data relevant classes. + lazy internal var contextProvider: ContextProvider = { + return ContextProvider(with: datastoreProvider) + }() + + func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + setShortcutItems(application) + return true + } + + func application( + _ application: UIApplication, + performActionFor shortcutItem: UIApplicationShortcutItem, + completionHandler: @escaping (Bool) -> Void + ) { + let handledShortCutItem = handleShortCutItem(shortcutItem) + completionHandler(handledShortCutItem) + } + + func handleShortCutItem( + _ shortcutItem: UIApplicationShortcutItem + ) -> Bool { + guard let shortcutItem = ShortcutItem(rawValue: shortcutItem.type) else { return false } + + let alertController = UIAlertController( + title: "\(NSLocalizedString("ShortcutHeading", comment: ""))", + message: NSLocalizedString("ShortcutText", comment: ""), + preferredStyle: .alert + ) + let okAction = UIAlertAction( + title: NSLocalizedString("ShortcutOK", comment: ""), + style: .default, + handler: nil + ) + alertController.addAction(okAction) + + DrinksService.shared.drink(shortcutItem.consumable) + window?.rootViewController?.present( + alertController, + animated: true, + completion: nil + ) + return true + } + + internal func setShortcutItems(_ application: UIApplication) { + application.shortcutItems = [ + ShortcutItem.first.shortcutItem, + ShortcutItem.second.shortcutItem, + ShortcutItem.third.shortcutItem + ].compactMap { $0 } + } +} diff --git a/caffeine/Assets.xcassets/AppIcon.appiconset/1024upscale.png b/caffeine/Assets.xcassets/AppIcon.appiconset/1024upscale.png new file mode 100644 index 0000000000000000000000000000000000000000..bc5aa1beee615e01504514ceffbd1c871ff916eb GIT binary patch literal 103345 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

@h4_FOWax8P1Tf|EHrL*WVWozw6#BLVYG7;V zQccq^QnLT-w4K3>W5+dJpGl>)TZQT3%7GR<#HK}83u_X7ds@1o?;H6dKxyA zdhD*-zjkYYtx!&DCimL$QHtGo+BV_vf%=Q}1;*dwl-wxcziq_+RF5br9G!~RW87=9 z-V7dbrRidow*0C!$B<^1E*NNQ!EeS6M+Y1)B|H07(eGAfy|9VEq^O=lsA#o$@(fX8 zLTR1gNwuGDmnqTSY#hD2z;Lsk%l`fz&c(Xg;fg9hY?g9dVDi_i(5XzFD_EXPg54_2 z1dn4o*f(F!SOjx%I6VpN6tNqbEvnq!n-bqc9`egwNpxtfb>?cW_ZS^9jWTHw1DzTA zWU#y!je=bnGC$|kzKB=3jP8)q>e@>Fi)zWqSL`X$TA$7ZqMHIIr+E6G8t?;3! z@pAk?N|sqQ@;A8BDuMB!fA76n@-a(2|K5 zOcBV?rE_7=qL%nyKGVLD%P8Y=kuQd;H?6np^3@oSmkP{}yT~eDU z-h@BXZe=S$M3zvgl@9Z`0T9o78_hS(D+0jgL{D z@cJ1|kI+a%S?8Cu|33Go$-W~b!cLiDK7~b~d?T&5AQ|WBvynXvJcX&+R{i(B#)HI8 zQpyxkQIoYJOdX${J1OROY$L9G?c2tkRL0K5+1r|-98M%@EVHhtnKX@RQnOE3fi&I+ z3(zA6&z3FwqqaK6Q#Ix`ori`W75Zy7jYTMP1yV%5^4jML9I5#K=l-R?zwU{n74Pco zPu6wB>x-=jYuzw@mmBu{{5wd|mIB2W>O*$i=Yyqn;VyTlf|rfM%UG)&4%{QYEg^bj zx`f`Kl6L)?q{nMY2abN{t&BL8Cx*G=w#6)$r$gJMkgIrzgMnWRRBm&K*Kvsle-Hew zLwa$f%JEz8PRjf&yR^3#jW28-gJw3fAb0O;{&@Yy^^E7Oed=77tTh$jr_~|r7)%Cz z+;cp)*>$%2YYBn&NL_mzH~gyYwfH;2e<|b5Di75TgaPPTg>k%EEvaWHWLbPweR5%g z$KpeLz+jDE)`&gEpPFwwqB9QSq!)=ipCS{?O8cT-Vnxh;BbAx+#b{|nqzRwzoVAU1 zgB|H8i=8%I6pVogaKc)1__%uQvVTy>n^2nFe_$zxrxA#~c?@hY`8iDGS3fA{+K6b( zqiwDCmluk7vl+sXFGtB`pgzK*S?FPI@=pucarMMAFdRu5|j zyGoHb3tIz>0+p&=>Hepu`K&wG2$QD;?UUmF@4ynTTA z!cII7(nF*DR{W)J?+kHEr0Kvtz-+U|{DSmI)PlN)kH-VW@t?g|3z=|r!>Og~K6wq| zt8s`@JEWBj{CZ+5o74Ck%x4wh@Hpn9k_Ha)BArCny3}svFXvySeSXfMuMM|(Apfn2 z$D~u7k9T}q)uhtKo$xl+am-=nJVa42U-~%pkFF))u?iLZO}T0o1CPM>6-#_UQx=`Zkr7Wf4_DUOGp}t8+9iMhuY$~O>)zG zGjFf7L>l)-+<%Ik^)#k;VU)dE)|L>0(B))D(SKOB;3T=GjpFa^6fRXE8llI>fbw-} zZYz1jbbiH6g5!$tf+vwiQ4uD9L0pfJ2q%Aq(HrrA0y;KULqm2c;BqV;It=^m@#a7D z(h^goQ_gGZjMvF>`Td=5AOpx*T*LUlj&q8Q$OIg`M*YGpPP&^CP?l`Fq+$C-{X0uHZtZrq5?&yph()LM?#lb^G$yKXEdEeuWo49fgoPJ!c=NJ=1_ zZMDXL_Qw~{^fdlB*lAP8!Rnyz@-F(GE-c}^cvFP8w~ES@ec2}}uWLY-D0M`KBHVE1 zx?a+#_v3fT?7{zhMGFaB#atnIFVaV=pi2xz(9$wx~ge(1(k{tk3mM z?#h16$#C4Hb|f9$gRBf+?MFk&KTUmmLosy!`=U-aE^Zuef<_^rsKnvlBj@=u)?EPn zKD~{J0>OU@;Rl|~3m8M)NrBb0G}{02>z^X&HtIli{3DC`0&rL?-*Do2Pw*t8)vK>7M~b7R5ZfyD;Ap1F zsQ-A5S=>*MkW6`+*CJWm>R#gIXsp^#LAj8|%KjQ=bLdzj&V}ykHLp0yo%^R~El9|n z`-+$w#st!ONSQ**SH-NhNm{}C^!WFU5Q@cZ`(i5KLvPIB9_BEQK!1SS??oaWOjXWF zSRSOpl8);4oNaP}BW=%edaYPQD|tXiw$dP1Vq00sOF1!vOBM^J4>UgZR%v76!XeGv zq7p9QReFqYD;)HW=ko`!c^g{&C+knJ_z-C3oqLV5GN1oo0#-K)HmKB&4Y$VL`m5Xy z(ILk1zk5eMn=ibN2%8+kPHROfqIP8A`K0)JG`WnVB*XkKhXK($8R3B%wR%K8rbnZj zvp3IOt&d$sK?i~RQ-y?{`4gb^F=q}Sbzq!z{g zt+s!PZ4wB`>ZktTONn&Ii1_XM*!Go9u7@w;LVF4gJr1KQw?_CaB(r*B4!yGun%F7x zS*cWiXy}OE^ggUpjI@jI6Q<*g)`w8|abmT%XXvswg4X?jeUq(Ut;FUm3`E@amu~DSKm!y*s+3^ zCywqb3;$fh2*To+tZgM0u-taqC%ow3tGO1{DHl@9_?~?rsrZ{Pc*KRt0wTL&*8DNN zp9jG2BLB+mrOD-MsNaTd^7Y0>7IFUodtN~t-@%8!ho}vZV>FN}BXi^EKA^enT%IKM z)TNxFPx{}TpL9@pV>E}@%WB|M@Tu{wCM61ud=XSPo5^e?B%2)WHXpfyX?MrM>S4cz z^G8&N+M?PJ@lnvKC0bi+9>~?vYGzvFP+5hVfljEk_ng{ZTxiP5|6bbafjkwvW3|C{ zlDWmlzmK7W5GsMQh>exF#(00jRgIPiNHI?g^1a&#^>r z2iMX2o>&2b!c9!+OJ=pcwZsUtYN-02@v;k1t_b6AYVGsd+qjhk`XeIQ)w`g|(kKGU z_?}m))|AN&afYa`jp4*JK>amLZT@K<;FrB<$bQ}RT0vHu>mgg?Y`I$BP>#mezXc9v zK=fS+f)h`AtNU1R4}5?U*BsiutagaDV)`7CtTZqh3v0*~r4Kb!2lw9%|GQD-gU<=j zulAGH+sCnO+RN0v8H)3|;Xqr@T2ov3FpMJp)ZF^1v1Y4fcx&T^mL*MpQ2K#6RR2;r z>;tgKhs6J@?d<19F6kgHAIS}(2I3`@>J>()$QRxAwUM0Ep5ghW0$#yUvbU^z4YzN} zd=rpJ^6_}VfJB6Wt@RTk@kHU9>>F7g?4btnIE?xJeMu&jT|S==-1E}oavBACZ*cF} z=P~5&$e4MjalQ|V4>iIB`u@vt^-J_m3p3z@bll3%F`DR<4n_-bKM7cQ5#K+8Y>Df1sun6`g z9BYfm7+=p1E-5eES2zSibro}gJpls((w7) zaJ?^AhMx!vr1(RxXlHlhqr~l@iA#8z{agoWtOLmT zkwEAS50hfvCnRd$j6C)E2xX>tZ)S8fgYtKMNt(jyCImLHM2;M9RZmWgwP1+2uz=J@ zCsG7$F=@~M^yna;=lFzmS~1$^HaEdLiV^I9THs!IgU`K7EMeV9p1Gd^VdnZWux>-E zAZY;!nt$bndWRNIxZ9o?$DGB>c?#$qP})M)-pVLzT)m+IT+Y$wk;tiLV-U+k+S7&rRQ5LXG$D&iqSh-XqFz~}n%4Bt>J zwS1uajwW>g6utX|d|o{~OBx?w)?O;)2DD!0yRlP4Ge1nbMZQdw1oTg$05$RJtHP^8 z+JGFZqn%JqAQY(!DK6sHRF?KNpGvDRD z;AG&fiZHEhmg5IrZ+NNYcN`;+Yi>;r>&E0Tio*CXi1nf*m~^H1Sh9GLKt`k|i;5XA zL;|d!EpWWDU1e>^g_0=%9cBxy^wYlu;xmm%h-bdttu^FN{2pCd`}fwLhl~66 z5j(nA?a2w$PdR`QtY}vE3#tQEW6UopCScL>)2q|j)bQe(EsT^Yl zxIJSflqi`q7Y8GM{YL^k;afBgdH!b22=PlhefPR_QkUrs#Le7#$C}B)h^~E(Zx@}8 z-n16=GFCx*X>mkGN_kuS2dg_lHw~kQ9{ZA>{rcxG8HqENBZoZ@&XHTDTBwm^DB1uc zNc{|b5G;9q3e(MpbIUjs5en~{?@^9WR zfUZ`=Bk{2TMNZKkji%OjE~u6O%zgLymuM@mN^X9*-V5zKI@lk#E%OJX_GmEG;CjEx z0D6eSO7|X6B|PsJV8eAXW3zIN1xA1*2Jf8QuWM)Dy4KpJS=3YBhPPMCRJ&_nKxq(Y zwG}&jxYiyQCYQiBAG+6TUJqqITo{uq8Hy4?B?d)^?czdGAj+0zjQrk#6cGWy(k?k9o0Yx`oAiDCJU60!s)G%4a$M?u3Buyg7W%6RuCs;AE~eH;xeZ7R>~uz zD?UAxh5Ju4){r5x)y8J8wI@Otzx<#XV)mGLwaPTET+O{b`id(*CQkSRnxN(pF9K!e zi8^P?2lfcRkdywUAZZ<%J{a=@-NjA9Adfk0;so8QKmN9%gg|vZN3dL=>%*VYzEt@X zUf}X~-jtF$ATM9LQcdpE@c!qo(?0~^C0QTK??yYjT@Y0_J9hIe8IU)qe^;$0{wTZ3 z6EJ=%?Pm2}U{mAGjTTP96h8s~+Xe7!kLd=_-b<%_0eY%L;6kZ@?<&)&6l*6Y^UMbK zDRk~~j{4_hPk7{g8SneP1Q%oon5_1%2x8?z_1HI!M)?9pir>S$(JsqRvkr6Pn!=Fk z(q66jjH;nD?}6a;4~4qX3#K|bWnOZ%W!*jt|HJE4a_|$sO!lasV$+>&)_M{D#p05G zj(N}>uGka4C#FdV-LBu}b>XCi>s$L*4iVzT(`QHP_YU%6$;8X#(NCRNuDwYyWOk~t z00cRfnXs@1WT=esl#Jv%;5woXO%k~3$B`^U!z z04E^py@#)-HJg)R_NBY@QKGIGn8bpZ!+`~(X0;D9=@lXSse$a}1*J~r1l~vPk^iE} zY`J8O=Oc8CP@6n8-OnD~DKKQ`lkQ|=-{qI%iPo;NmkV;j$Gm$vS{ex>$B0DssPl8} z#fbtLH$iy50jIiX$8~JM1=Kesx;TzFN^GMdm+Tl4S-Dw@U};<*&Dl1g&kZpPb|JMn z%BuhI*1+Yn;5#`&rX=9HBc*I~Z^z?-i8XX*L8=LU&3Fv;FWkNAwk|ANJVxlZa3Z71 z{W4`zu^Yz$Dx4CgqiwhRjI^-3I54*XOx zubS$%4z+v~S(Mc1+JOTP@Ax)9W1_h$ylt>^qJ|C3Y|?~SN5c+(R6%HO1P80D4uIEV zadF3+bO~dfn@Q5GPm{v@Uc0B$nqM}AIB>$Y{&Z zM!l3M;x52&&E%BXhtOpJW`P`4QaLyw3=!P(TIr7Uy>f`c{{JFi1mr&H^Sjm8O5#$e z$3NFZj4h;;@tW44XzN&tb^f2B+-3j{#xwel^_dwg9&W=^l*#cwom@--Qx>4oG2jXt z>yzc+yaa}mFcDm3rKYM%w~F&tesze;pH20^Gqam>s*ivlC9job4@vJat{bf>gB*R& zDqR)WpBQ@6w&wV|K=zY*xxden4ae%#>M51OUe@$$yg9Y&jh8*`z>=W$ClQoIs}6GF z-J|{qs*~EvhK3T88DDV9R|-ucrit6?QBwPhhtUiHLUE_#s~@Puu;E37BR#4g_t($4 z64I?mDf9BSA2h29yEtsK2b%P<_Apx#z610~=Q}R54^HHid55My@d2hu1JELZ%&*vW z9=QXz=&|m`AUwoc?J=M2kw9{;xG-O?isJ)D<%r?ax~`^WC(`@t+h02lRD_X?nGOro z@GQQ~`9m5cNqP6s^4|<T+AAA8pY%3Q*^z>gAXuy_nnq_eAFv>g~c7-t`;Nk z4-=O%(g~@zwAk!fLDb-4&>1s8tt5%JCoDS~xt2pqL!%|tzK|CF^Ky)VfD4Dnk`VUj z1736dqii&f8!at$9MLWzat`IpW^oLD%7Nmp2T7gmd5p=v7pa>5r&|=a z_w+`y9)@%L2WpuL=C3zu70)yrl02fQmS|#PtRR9qdkpx1lZquURDkm!)^i^d=MF1h ziTA#Z%%srtbT?8tkK%RLV>HgjXoFjt3_cv1?cZig?sfMDErLj-!g8Z*rtP@`z#p?fX&-}kh~)3I~k)6KxE zaR<5Od+zm3I>cV?kY8AI(>tEn+|D10#SzySG(ZX(=2sGvFfj9w2!Jly7m8YLScP9K zDZEn4Z+s|GSN%m6rN4sP0hA@|lfMJ1Dd{*e-P?0@{}f-=Tz$WJm5Lb%PJNwkyq{os58&})2%WUP0Mg-+3d7YjxA$wo+U&g4?=(_BLBxh)DbPj}j zBkGA;$%6;KWoI>mQ->)?s>|d8q!Js?^Og|#S=mNL_R`CClnDP1sLlfwjWt=yYj7ZI z_IdAkcN^a~XWW{*?WvhyaS5ViYKY4SFih$|1eY})#;eYv6x(tZypxd)H!x~!ny-Hr2SHiiV6$Nl`D z6M96fCah|5DdC6;!3TUnHIVO*;|}j!C9~)sp^Yc*!2@e^40uFv4s40|$2fS~57wd% z(;WWBF3Fcyn?5qC;A+jB=m68-PC{(FBUHWpI`Gx4jdU-e)?z zGn#pB(Tl-~A@AKpSM@EfVMGtRqR}I3sIrn0W8~ovtoBE6)4$@kN?!_j`MRJqe-Y-U zjde(${RAgt1)Ydcm)?BNwVi7z$4{=>#0*4SWoB%ieZ!1Dc;hjqtBcV-FENb)E~20A z*b~)w{9(92#Xp-4A0RI%FH6GumnEkqfLgDL9LWVM%O!MhLXx);2f)0%wP+kYv#IaB z_D_mWV`9|9*FL*)t}F)U{U%B2)%sGs6{r5ieoX2)>{tJ~<&wAvz?UUOsR{8Sl0}s_ zo@O>S(3|P^sNA3!FfO}c{_%<7uSWle)jlDX2Xte>U)gnMO`hxG0}X2ooG;&q>~+Mj zcUS+$x$mNS{Aqe5PO$kQ7kM8(&|S%IHH&3}i~@ygehFf{<{z{(=?<7Csc;f<=o0sQ znN?)c6nSrS97i+o`HsZA_{ufWONvb$K<(LqsEsB9;&6`>&<+n{j6qE3W9})~GP%Y@ z<-a!vbfP|Xjh<(a9ZTJut|>V2BjMhYFJ){MNg2?C{{b+zr))p+d6MlGLH)7PYX_wo z{P=xdoe^_t!t_(lsyq4&W*?`EzXO^(W5Z}JpJHdBGSWbZ^C}vN%64{qwr6+a0__6q zUk$AAoOG}rw-zi?D{#Fveg+&;yV?gDW z1rIA6{MVx5CW`avsZw`hfhOz+&JacWzH~RU4Skyy*@uS=wYTBT%kBm(^Q$LXgU&Qg z;^;crh4$Vf1p?}wqND%haf|_8BDfv7UK?-g)BK_WY=GHq0fQ@IK>Rym4?B81cQ%7X zmkF-47(Pr^0{pL5R+|DSi>jYnXit_+Sf96qBt&)+n{pLYnolwU6tO04ipI;+_~y?o ziej4ffwks2`ScK4<#^V~N~}NFTnuZ(AliNY1Wf#h-@9>xw^2td5mKmrYVXWIf;fNO zO^F5fj;@4ckYqX|b@SAIRoNUBS{ddy*VO&Ml9&W5oZ<5oCB%||cmPc&&fpY7Lcre; zJBRt}M;mr{hqu+kq;{PL5)O3M6@ckggsmOVBa_H7o7`x&7aiz!X>bN^ z)N?vY!mYdGl(w@-EUfC|lQ`dFU~T240!7gw{dmc9z7iGh*w#;xzfS={a9KI*+)<0L z+F|6o#CPoEv+@WZk2sI=i{F0i*8fb#%M1ebj@fSgPubzW@CL2$ByqoA)!hBx+eYIm zQ!ypfCa600-Tqu+V<;H>wk8r9IrZCwqGLZUV6=zrvAM5HzX;BiQ4jog*-SSwDhv$X z$_QM9lN700zie2So#w`rU;mC%L8YL!ilXh+pw@0MkvW{!j*5NA7>1>u%83JoQ*?o<5)YSHU#MR+qxjm-WiV3Z8MzNj!7tLxe#QA{cf&^ z$qVaTYqPwAZ6z%mPdQXCr59b<^YEA%cTfO&$$x)-8b`(Fi;<8On@Ne9?Z1Ky_;ISe z@kQi2+#8E@W__=gqW0#G3n{>CRER%j;r_ma;Q+z%$^4|9Adnz}T?Z@rfoXSiBtFJ6 zxQte-MMW|@w16>+sATZwHf~ZH!uM+~p4(!7;p(Ud9CqCys^O^dF>`s<{o|x^#fe9i zce(s{XV~#EeTZ$Brpq;|P@Ou)gEX4O>9=(V8O#$vZ)t(`rX=wM{)o5?4V5gGT>k;I zi%~sTX#R?s;kGm9`&Cq9EDvheQH{0Y@%IB)jBE|nK2B1CghyPveI78~#3O#|U7l6+ zK(c0bDPhth(dVc2#jmvHQG?UyXogs_E6=vl9+N=jcwa={l-0!4ksn_2c!F_0FiO%} z`N?kmY#Ky{3pXfHP*~g+G}vbtT8U~O8_5B8762Q*L72=9R2{YzXGSk0(6Y&m**nm) z!2$vW5=9K-_&JW8;rPlE(f-{f<9v;EQ4ezpxbVGW$A2Jqn@*yM)_-FU>$B5K*m4?AvbL4nU|yQNbl4YMvDw}F777IIHB4te#2+_8;4z;6xIqOpHvznB z|8NAnG5d!&%gi;;nfaNdzQw>I;P-*(&)xiw;5(f*IQP`cG2<$H9TrevZ%Qw8I=?Oa zXesbSirG7u2Y;(D%?^@*o=e91!FB&5yVlt6^l|T{m=iyQ{Xw-M`ut>8YCt!>j-{oP z;c%(41Qw z-?OOgmc)R7apBY5^2WC#Q?9M(vQ4q<02J!_(zu+(N!!OTV5P^xcUNd|>SFS+X`@+n zHb7qlIqT5P1f3qw_X;Jb*^T>#e8&&;H3ME5r*yA89dUS2`3x>Z<1n4(5dR4txO(uc zOnFwDXZ+6Pt@3h$4t5$Zkr(VliNv)x&kcwG%zOwQl5DzgcsCI3>w`Hu9G!Q!HGzh2 zFzTfzW8m8&@6<%8h^wdpty8&ex#ho{cbB&yj1JEa_5#fC@4 z9TIa`@O78w?0%*Y4lzXz==pXc5Cpz0nuQ%e}-vySSh0@ z`(KO)S^_qZ^z3AHA~+IuQTqCIq&X?Y-)>VNNgsG~VC%u-TlS_g*?8H&r%k&-mtZ#3 zpO{B=-{$4x{b0|qu)NndQ2hUO@=OUZ@f0FRsI(a3GAF=q2w`?_PM%x;x0H9UM%Ic& z{D|+`47H-CDCB>kl;1WZw)yhj+?{??>F1-|vqk+&uK(1&^l3E0o;u&|vP%ym=}E!? zJPP#%A3$d+Js~$e2I$<^gU-62Bw7}DSoPGa>~!+LmG06#f=71$NC^&RmfwA#2_%rL zJiYb*kQ?8MF&K5j1b8LUs1%->qcLLpib*&;Amgep4|5F~j@d}jdtYJ9z)+l_EJfR_ zgV6-0MPO>5rvJ3~fpYz0*%Dy)!-)Q_H5m)L$M0kRn61ZVy9M>&(fn3X8TJ)vu`A)fN zulUub=W<6=_MV7d`Ri4lf139OlkM^}(WH$X-31#XsXTmju8Ll7I_Nmv?d{n&6Z$iU z=l$Lxgy7wyd?T_JA-0t0O@d!u307}ikHmG_*2CwTQtn9%^9#5w zccLN*doMkoFFOTX)n1jOk?sv=QHw5a^(M0|LZhMy7?$_o|Eo2OtC;d25@=xp9O#a= zbCvh#vfjG6$BA?PXtD6_yRlT^e-?k3)TzwUxi*d%o)>!3f(;V1|#h?~X&X?D47w9E)z1GC&mG6GtC0ZnHVJ8r(_Xo<(_UkzR zt7k~qGHNyr9|&GX-~-~}c|17a);~arw_UKJ%SNUAEHKL-EIEMxH3+$1zY0*Yd`iQ- z0rE2liB5X!XlFlR%&XA=?s=QHVMZUX_ng{ukHicO(`46?Vf?j{SiL6f2 zH}9MWsi#h=p$X0$!3Ws&DaOH=wfPw;OOo`+tiz;S*Z$g~Ngq#C9s25Opkv@-`MCTt zm!qkTjXfRd>)m(c9vS7G=kGCg4&8O06LB=!6lqdH1*A2VIThETw;a948|1tlkf>`h zccYrTuP|CeRk1no*^>1I=HlLG2uF%GAM1Umgl|a~d&L3X*P8)7$Q@2a!fu^%!CYyCIDdtD_$TSrHjgU? z%Bncl4^PY>?fkHnJI;p3Bn`x{4f$}DO{Or}bABJ!C%KLXJ1imuI7|QG5d93KbZ|Br zL)DV)iT?A-j&u^%mkPiC7J3ZC$SE=SUg~gL{J_cxq52}~8hJ7I%>Y$}G8|lt;BP%B)9hs2rZ4svJ4BvOPe;n*jyvpcZitp`>(br?@EHMKpWDAZe%f z|B~3Zm=hO+lYTu9!vE8KNRq?-5;jB;%MGx30q{5atKu>0?MfNl8Kvl_lP_!O(_gME zgygw?0D=VC*~BqAL} zzOVVbp4WB5bF7a%LlWrxMGi{ z!o!`~ou?{x^~+OtySFQlxYSXfh2bba71!Q)(_Qqcc}aebnzFv$lPn$^Kz5;<)>i8j z_bMcdIG-CMRZh^|zPe<(9KDpPKd0+?I6!YqCoszWccI99|*@z?maCq!}mn% zXn~ijCl}o`lc@GjsaG6IS1G59Vxx%u^Rmn{^LbPL2W`p%vUV%q3$&$++Ix<&5HsXU zQ6XTHdpD=7GG9A~$PWT|0xz8Djbn~68AK7vR1`1x`L)S&=$wqw9i90XzuqXwsjJqf zVVHWpK&l&O6>`-flc$dzjUQBL|N3G``+b{3mz=36BhW;sqB13lYLTgHtPfO!%g&yPJx7c+34TQc0W7k*kPtgmRP!OL%vedV3tnIFwRP-*(}rk z9{SxMN&eybVViaT8=h_Zc6jv^iMsJ;mWg^o^}UVi>u6p3$(aUZbK`JxuUGwCIhzLt zi{n_t^juplwu)1em+W-yy@wIM+3RfdaB{|X_^4}aXfVx=IWf|TFm??|Fe6B#xu1?) zbKaNs`;InlmMxBt?av1H8N=501SX~pk1x9()oli4??#RT3irXDNr2P3P(XGgdQLcC zI51AuPXXO+Mc4~`b$BE@YlA6U8tiUf_3*nfu-}e3J!Hpaf8h`Lcg+;roV*j421%@ii%Ueh zeR4A@*g1hI7>Hr&%U&8F_=Or=vMd8d_m!m=`|sz>MBcum{c(uAuXZtKb7;|W`LUt{ zX;ht_xfrH)^<{a)*ruE7M4(Ts$5fgAVEvV+MtjwB-MglITJujst%l;;ZEPmJU5)TL z>H$s@)pEU!-p1G|hxz8B@vZ>{+o!vEIYKiTUXyy}#x4PqLq`v=1)b)xlO;YAfk)Ul z)2W<7JwJmiU30Jr`=8b;R`w3E=Va!djNqy#jN=Fb1GxcJMK?wjFll`IyS;={`6f#Z z6xJ(k3*m=n6l(Jr_?TS9=5-G;44+B$ z@-zyN5;o19CLZbEy>Lyf#_#q>YMY*``|1f*4+x|hsy}EpVuxKwrhaD{dG*Veg`!K+ z%++Jx>!XkYyDlAh63cb#yEmJG^DE%(qYiI;OosOb4->h?^-Amq3Bu#59$#J0pTG{6 z%P;n#>X_@IHa(?(I@w!?;|Ygv*JAzf3IE|H>K2WYLFfUE&-Ct8iF}_gxQj%1je?3w ziMZ_-VNAV|=H%aFjva?;3pgr=2TM%+)|9!n5+2wlz)>)iW>5~*H*yt560Vq!Yxtwb ziP(sXEERdhJ%x4mlI;G&2vHQCq%Iv46j2O30%}9SgBVsb=ZjMhYjbd#7hYjUZ`b-l zTa-pM>t~4Ww?=^&ocDHV5iQya#DZvE$Ind9G^RNkKqWx+FqJYb>18ATHaqdOuD@p#BnX$DlQ(&HnQ(me(3M>Hz<2f3_X`%ERWt*>BV)$ue*;=wuZxvo0 zz$G0dw)rLZc-7l96*hM#?~We&AyWeqtDnmE`URyPI5!o($L=pW8~K%VYc&GrbvXOT z5jPmKS6{VT7N(A|!!bu3$tK>2bOxr;PhovK^60?ieTdNVeBg+ObJI@Bq0^o^LDpqw z&F&!wZbUGCD-hkF{4mW>Q#^*+Pi5$2a%7k{68(vVDf1)c)&gJ@{=p;<;JxTJmar%X69P_Y-sT_>yxa z{3M8`{FB1p9U`Q2DN48vL;+{v8Q(r$d9Mr2r{bAl(R5r4+zc6gtvXWmnJY3b1~0EH z_jLKCwg>H-4p+WAkWmu1&Wq$l-*%!y@v`~z`oWKK80S#tKwf4E@!vg`=v(%O+37` zd4U?fTQW?PxC8`|{rL1!6JT%ny2CSCekz!bcw}8sB4oBsF_YAJ{4j7HFVm?AjTj(S zvq8^_aIk)m7nYLaHM>~&__b<64-;+K#;a2n!dIKuc5A$WRyq^WWXYo>`~`a7@1z&D z68fIm;yCWVc>N*;23!90=6)!?!h$v`q~*3BM!w;DU&@Ez5#Q3V_~RCo7E&%z#v2;S zLEh3bM$`rIS*q7~R4-hNNEk*JKp)2o+BSls&B#i%z77-f7(Vc%8Rj}t@YG83ipC9F zO2~s?blNDul-}qS>N86FJ5Hy+ZJs6Zhm6qUG^;(Moh`feBq23#x2(BeDS&}(0WXPd z={gW3JyoWB`QhF`TFJAR-nOUT3)(EZ^Dd{%PE>R@hz9u-z;ajgb>iIh3=wu>&U#sz z#Plq9n>fgegO8X3`;x&I?tA!jY(ag76sbsoyXE0wPu}Ril>GWPPN*WQYnZ*2yd_+4 zCJy@)bBs7l57H%UuhP-`-9M#wp51xW)bqCbB28J22O(0~vyq!wvgO}|Z&SA{^uvNZ zvE+;Kba8&*6!Dj9iXhHD=yNv%FTlrx@JTryyuA3f8`+2U|LoIWQ_{*3p%d3fh+3KA<3yNzxx7sXH(bO#ny!AHS-;J z&K6wps3XP<o#c4y|si4i>)?LJ2R;s;c4Oxm(|s#)ycI|sfxN~0l}Po&reZQuAs z*A7NUYtkhxs+7O)s`CB0D&sCVzZ*-u57B7T9&IeFJbzS6dXEp4mF|1_+DCH53whHi z?n>+(^0O26*D3aHq^V=>l(|XA`XJ;v&#%PFeg7i(*dbMuNNEZVAi@A?Eh!T~WnrX! zW)X9($e<7JJ%q29{FRPDV=(un>Y3uenM&?%rHq*uPan*XlP5@gvOX6K_fWh0*t`4Q z(&Nrob$50W%ut&j-@dLHk9|+}vg`fazhia-??xRtmyu4OwX)p^or2PjUrN8?5& z-6(4ZOnk&&GuWWz-b;x>CTH8{aEo_4nmoQEire3Rzx^*+=WJ*2pP3W1BIhy?NZlWv zMqtU*DEj(?0>t@q9zh9LdY^=OnwaRHT9|Rg&RHOvP40cav}%DAWj*z#r@`s;YA!kD zpovZLRl|?AIn87YY%z_Wi{V0xHPr>U&w_mxTueLT#96PBxcOfTH{f0#xK30O>Fb%;0=!)+kEkI$76ccz|!%AUDLX=M$U1eNNBKjHCx1*lKYL47(#61d-8yGJ_et z@a>!DZeCRmIcCH8kpZl`j{!QAX@X@it}Vf%Y- z<_kBQh1>H5F=s?j{3-&Mb#9aShk6pkPOvde_(h6&=VtkH21unnWpN-x%9|>zu{e+H zJkzC{VW|R+H7nPU=m@zo2QaRZMpHo3c4Fu8110&nS2>>nd!>^QMmK$f877~Wmv)~i z8;pg18FmQzSgA%Q0_Iy!VlZxEW~+h`G-flA#+nlt09}N zg!!?}nRO+d((H_n_m|Y~zc2IVSNuE<_5J)M@a$^7N7;$tlBDghMZ5M(ec)A^pBs$~ zkiWIJkT9@Em>bq*&eOu637dI`zk4|`$OEi72Dz6r)v1LY*c@ibBCJi^l8Sp$Ppx0i z5dFej|Lx)DY1Hn+@T*)#Sst>Knh*4ucw%a|gNz?$(;w5s(m+g7!zXG79E&egFw@Ve zJP&4On&^nEXqsB1i1XxbzIyVhY6tu3+B~aLZ1n9b(b(vH-Isq-5chIM6`tJ3ucIR{ zi*pKh*ia>T7c&*V?iEy+%5M+4xIj)qh z&l@|I>3(#T8_zg8^%$9Rgg7W%F2>oaX_2^iM0EVHCw$J(@3`-$EUgf817QkxlmEl1 z(`lIpTLi6S!8u$+XQS=O44jS6ISX3utpu0rBy#rYdwAv3UG4Gvo`I%8!*dR&Wo_%U zo*HT`-s7;<9W_)PK`X4r_KWbFZ*uv1m^2|3%%ugWpuDeQ`;nG8JqjKoR&UGd;P<z1~*_}?UP{E+K`XHBt(L=LeNkivofMh!k_)jXD0u#p)Og=**uVH=6aGf45kG2l>IkdX>JO{MVvyM4ii+=(ssPE+pt zWLT(vJ>PPHc3G-@A#DDMc)aexbvR_ng}@j;n05)!nEF3BuF8u#wR7KJvps=CFZ*mh zkH)hoWV<8gsdzldZQrt4Zs8}n|H&#o`I{5Be9ZLT7$>g3%NJn~`daY7Kw5m%(a%_s z6R?9>T&MYnqPvy&n=wYLqST0sPr$9lvF!oO>u~YVW8Id}+|=C}zfFCz2dlh&-^rZ5 z`o6n(0~{46*G4JcS1+Qiw%g#qXWlk=!_HA1TV`NbZCWj}SI%(1pi2=_P z*$VmVNaT!YKsQ^e!=O!yJ4*{&q+Yeu z88ngV(Q@^2pVZ4oOc7kDQ0C`!%p=j_FKn!9+uL#p7H;gB_`&Td_u2FKg1>ypElMDS zx8O!fHdlb(g+bgRqY`Hj>;&m^*L0`b!gdT!oxLk;0Fg8H4q>mIDaXfMK5k|RUghg^ z#3iy^*aS36OrT)xtu4Z1DC!n7jrgCA*HmkGuiXX04ngrRV^WJZ9e6^0kQOqWqCpy- z*Q_T3g~7Zef?0|Z`;&B(33Jpf6(}Pr$idBv4Lf)dclrd422FpvX%3bhp@y204Ujc? z6jgsAk^E&ZAv>k8F%|ka)#;d~76!HkFyXHf(>-B0zvZfCZ`%E&PtTwq-#JyEw32Ye z!@?v|YJ&@)Yc~c$H%vqpj;Z&6HXt7yb>=nMGsqIm3nO4&!$b!g2+QIN`bD3AHDr2N zN7{5?2o6WDz~*^?edsd!*9F8~kwS&~j6v55rkw%x8s=uIB+bFDX}QHK2Qf|LWe4L= zkDcq|`{PIya9<(PeA60X#Q8g z4rq=fk=o0O)7`rZF5>7d4x5z-%6^J8XK0{W*R=1@#^SJploZofeoa==4O=6B(Vun6 zJ}H*Rg~d`iQv20-m!*+`TDz@gVV(dz;laOzBiBs#qB&@)BO&mYL(d2n%^rVY;m+|o z_z}&8U-O%(4iE-6k$wyoW7M@0>w=S00}0KEAJFOHo72ishb44bfety;%Bti5xih)_ zCnD1aC~JI6;cqn3vLi$qC?OOFYrs1c9vImCb1{IyeF{=;t?^gBm&ReA9@i^HQcx-J zCuJpDdKI3qXr`(J(DT`{p`!-HJgLRouwkUWZE6gw!*Xl?E&mVedt_=(9G1?7nxiCXQ8{q=3gs3+)=_*)eq{{D5gagM5aH7m zZqZBSRMUCc(GFrpt1>o$eoP$DFr8afXv%fz_iEGOv$W`L<1+10Q25~h zy4L|J{B1%>hVob)77J|+)Ku~UMB5#_-xq!8*2eKdmb^lAgz}gh-z6b~OpfMYqKR<| zL0?`6<{u&c%xc7Pij#f)g|zcD(}{UcG^*3zh*-ck{PiF)A}~OwA_B>MJ=AyxiQARO zsOd0tIOJEDz@r#qWH)=*PRI2AM@TNaVXpNzE!( zBATVG@fP5I-8|D=sN{pOy>1|`wxo4_3E`LYNhG|IlE!bmfw>7~LT$mLIJDfj%q@zO zx;5`cK6&33H^)CM_e)gYLt)y~-=i#85ZGI7Syfv%F;*JeCzXH^qHK;dM^5z|#}b&B z5;y3z091*3L{BQp(4gWXeZWNaU*}oFCAiw?kxD)pDna-{n)RDI9FQT!g{o3nk&pk5 z>0f5zV6n|MOJ;n4Z#6_C3}LerDC6w3hX8>375?EyX4kil2r{oF@<{P)WyH^)1}j4) zlTzT5zzRx6A()T_MmLr51u5DOzrK4!iEw#Gmzt3KnULT0z5XPhOdx}) zq)g8f{ov`DFW<%KLaI`_RH&=99+ph65vU0<%Tv?Bw6CD^KLmVy^cSd3q%m2IE4-Oa zk%Nmh$@Kk^qv*(85=5-fcDbFnorl0b;@X;Bgq?;3zEr4F7$G$y32sWBcQcV82%a+B z&5QHR#|DIfd7d0el)oLJS=VC-XjmPx5@|Dc9`1PdU9aOs%$Y}`wo*pj2WVGtQr^6S z{4ouqn}|Ky9+?FhgT0iX_!*sO>yjopji{&Nb?5)lh8&G=8gV;G(I^mn=C)SrT$7q;j2%_q7GOjJ?cwmTO z2qcGJXq;K7V1(fp#%DGYpFrCCUzoU_Ba{M*h0%?a4`Nm!Io_sYEeYo;{kR=>3RRVs zUW&2)!jR}zBmn)Ujw>T2LB0H}bT}Jy4{WwEK#Sb2a!i4r{CWWICqzcGQbEs`U|jLN zY=7URYcW9;TJ^Wj;+KQnx+pt!8ih`Bftic`M~T z#oupj&`SxCl?^TPC;b-eq@|QT7tHpzizpeWTT1})SEL_XE`ke}w$F;@$G zvkAP>mQ4oX|NPq_ftQ@Cpp}bTl(IdhbYW|KdF=E<@hY;n6DG7l$E?K!Wl6E)O5HCO z_=11G>lBtsCP&G|Q}riy3Dzfg03JN?TFW0AC+#2LaJ6*{J%NtY_(ZQQ^yEMv4GasZ zo~XC`m$=G6ey;?B&l5q7_M>xK72ZT3 zV<{?ey`G{rN#CPW4TUB75*mNH;sTDNbyHF&OvBr#b)wngg>4U?7CS;m1bB^wNueoM zV$7hh%@=eCZaLj~f{z#^iFO7}y0Lvx&9Yyi(bjRx`iY3DO zOIUg*o$Pm8O;X&4z+->TN=)v<_iGQ!z^|9jAxsNGS-VY~mq3aOn)clY@gL&X(mt)c zFKb6AB$*i)bJVMGo_vdB0&4W1DAcilu~*=L=-4hKwiH*?UFoWvC7*gjH6lr>(5c90U&^dV6TC6dnsQDv%ez*R>DazaJ7650L}2aEugR$) zb6a>x67+m0;M%vMI_Gn~&vAPy&y> zKEEHr=|?Mm3)?|zeag=^&6<+zX6Y%5xA^=2bk(P~i80JJeh2SP|LZY)A%KL;860oU z0x^w8_NP5DJ;gN~*uw)YUxA(q=DwAr*vdO0s!B#8R`J|tK)?MGOgkL%+H0<(L~K)X zn|mD$dx%3{H_MWD`-7~A?#z&g4#Cfw6Bmd+SbN-(B1by4x%eQA5fQ${mML4V2hB1( zto$-MrL5&Sg-pgv{WB(t6L;_^7F~^fVmfvZMUh0-Vvqa^v%n)=RSj>x`ySO$ox=nf z4LQy(xPpoy&}Hk(mkN0tL6l{^PbxAd;yw!zF7&s$LR8A`I(PZB(-PWeJ? ze_-hjPzPN-n9`*{g?vxZAPg3!p?GS{+!0>#3JQI=3~LE7zn9!v>2dvCS#@&_WlQXb zTkUnd{YP5#(5P8jGm9r)o49SiZWBAHtK+TVYlMjfg{!S55p6b?xe*eOD9=jWO2?}( zJ|hXJgS_;m_2E6BUnRteXeGQ?xjyeM+^`)ktHN-jYE%>oG2l=!2VgQiQ9B!jqb zF_B-8CXB3O|F=UP6xIQ0=IQfklAOIFmXHO6;I)9bB-N?m{4~%Ur%D2snjq!5G$PiY zOq>L!f!{t{0~gij$Z1e69lV|j0)f6zOltn@%MUrxXz3sC3n2c1FJQnfqs#trP^>n^ov zIC;;fMK+tr=(NSb2fG)Z%l&4irOaSxYND|4JEi$wle-`scUE>aQ1gt{S9Am+>kmXF zL7gs4!f*9Sa+aI}^2AG3vmz}1asmfS%?l)rjNlvO1uh0jZ)**pQ{XKUogAU5WZo5# zn7J&tyuevRO+cq83f3|~7*v0HjLTOABP4e8X+XlyMFRB`L@v|!RGMQ{8tQe!zknHX z>M%syiTBeWK7g0tALMiF&L0eSYnl%9X>{#AP)6RgZNhqm?aW?BrK~ecqN*M^1_)83 ziC{+y**O)dmV#lAFi3!&9R6CYh6UoaDfP(eAc&vF@OI@Yyt0lXDHMiS|Lq0Y5arPx zXkuT>MjrUBHyxte5$p7!>-SP5Y`X3m^wUDiK!}j9MFYgfu7noAL?CGy#-B1F@{@3MVChT{%MoD!dtabA%;vI^ur+N< zHf}2BzS`z-8u?3>XmTfA=Wh__ZM;Wp9b}cxbx?Oss*s^JjmS{qf(rM*lex@b{K0t) z#YPR~#CHTfKrndpGan?FX7P!1nlofS>Cs-G{@m@OiX}YS-P%fFSmfBLvIEUH)B;hc zg&Kt?JHeIkx`>9#xvW|;#U>L|<$N>dI2|z$MFVR3d zz2eY|(+DrNsOyPRw7)1U>haY79Mz{Khz?Hzzl67?_q|IBeBFWB{y!^ONSXx2>kmrP zERblKUUjh4#frwNs6F=Ms2;pE95(7!RlF;|{8f$r>vf3v)nBsrFZv?r(#b*w?>R+t z-jAA_r9Q?fEJ!GP&!eah`wu&TggMeKFi0r5Ea}I4vV@$5LMO98uXGK;fG4V-%e|f6 z@AilPIsm$P5y@%cfjA!K)5KB|1GIOlYZjgwbb*Abwoev&9D#!n8Lat|2zD2&c}*z!6GhNFZIPV?f@+k*5i?iV>}AH0g(;oW@}arRnIn5TUu- zGD;}vQ(OvybN9>+j#&r)FEi(JP9?sZ>09)>8&o7vDzZwg2#)%o3?T%9N2SVoFOb^z zE-T`XwTHL#9%<=Po7vco)3TH;73z!-jj;?N@K*&6nr`qqsuoB;N9>Ud*5I9Hf|3uH z_a;E@0W`CbAZ)OJEayU9HhXm%AxOf*4TV~)m63^Fe-PU?=J?l?D3GGTjB2PjbK~K( zfwr0LyY&iVa}<(PG^iwrY{)aRlAaK7iRaqM>w`Ft17h9w*s}rmUsFVVN?O*pQq0J- zD(O$H3&-dQ!V)MSU3t0f&$oGnFZ87K3FMjF2%HA1=Ai+5!DkejdNCgEVpgMfaV1jc`gLT)R5P&(D*^($SWTW?Onc!Nu{s~*D$Wk+--;j91s0L?M8 zv449EC}|$lcHILS*}&3zW3uPIK*Ck~ zu9^2~em-PD|Cat==9$}#Yv|UT5n7d18aI;BVimCxaUl$nr)Orvx^6r?cr2Zevj>1@ zkg`7~rtE)Z_OF7Aq06P27Y~=k(MK;VJ344Wr|)pz_Qbcpzb64vbyTyOK{C=skLOHk z?~L5Z`yU`yMs9tO0%GeUJ?;`|{LH}! zSowAt?-|7M;+-<-!jQ!E94KAzoM0$)KkSl_Q|hzYsQKf352(UjR23_?i}TEz9dl(u zc`9G3WKc=snw}gOWN!D*=GYy5Cx)ul{H9UhYu@suYaW0m|3z3SXNid%G>ea91ZJVl zE9SKTY@i@7MmdghrKyLVz(}}ua0+~~*)&9 zO6e>#MthD^G4o)=uur?24C_(*5xNIC+!QITh;W`Msat$RPCl!s2`it5;4xm|w;L$UKbxxl5$0sZBivV2KPd7Rx( zf1^wHTa)M)JB9dU@}*u)$#it*(QuD}qN~K_5FN7N%P)4)jc-R)K^K8-;p2{?e}pbX zFj^mn0kM$(qb-7>;>W!L$-YFu6Fv;11Qf+=lAphzK@!A>2Mffh@@Q4!q)Qo)4=IDq zniVF4d09xHtBn>5-*Q>G38{=Nh2aKiS6HLY#JqrUg>HcO3z!dSqWP#p|KtRZa$^ma z?o=Ewn2`Ohc3Pnkx+Go^bBCdog|xI7E}9Idt;>*T9b-C3JJz!&aOZOM^;Ac%l|(W` zl!CtJ8*kIqfN-2nBi#O=);#`5t+pje>;&16p#Vs|4AOv@Tmmr7>%r;4v)rh-H$SFo zVJNywmN3uIj2^2k^UmKt`tjPL|7*wtgC7wVpO!gvAs$I-s6BC1;W;h`+DNY% zOZU^Ir&|pEEt-HXhZaU+%EI`0MHL8}8D%iAJT4!VLpg7KAcx;Hho$!r(8{mVlp$Y% zso%Rq^9_Q6+ZLY)AoBI#b|r%swxHR~U|$Ta*uVVvj*|3wjFA>>iCkuV#?i zfJ!48;f1^NNzI^F+?Z2(o}lcO``~O&_Z6tIPFD6O$saZ1jX??ua7AC=K`s=?C`=Y@ zVm?7jIw+=K>_F>Bmh~}`X-C4lVo<4_-XrQnppz*Pj8o(0nsAHPcWvR^0WZ&X#0O0W zo<~WNTjajmetW^ID{20}nO^46hyhV-UeYQHsWyk1Ac+cX%fjKXcbXwI;F51pxv1Z| z(Ig8JtfNqctO8*0ef5btebtN+1TGst$nV(axUCnGL6ec>{WS-fY(vx9>acX2$ei}B zIK;(^s>||D96rXjfi3ldpV9DW?BGHf4EV{QF%1!eZ38c^T*RYL2g*Fl3 z!@-m}BHa@Edr60=t^C2-o9;n&q@>!X%~KCePH}~Spx=gyYgIKmQw&PK(>DJogK;0T zUrDqK2+|MONiY2Q##q9_bU7uW0_V9ew)3N{eF15DDqX(Aqh1`+j?jScyFfxq!MF_Q zSI^X-Ik6}B1+>H_JpqYmWkVL^+U@c&tuCJYmlV~+!XVTmC>^J@t{?=-CMTc&dinRU zfoQk`zdlv*o5|zvQhq9dWlJK?KNjY@2BVcjYMd`W-J*6VbfgKsMvM40IlmWlzza&g zfF4iaxzu4`*u^gIZBI=Yfb&C1XfqYT%&gAes;n)q0;|mjjxnaw!D){qr3t=J*Vvwz zbHhAgIM2-2&ntqYhNeT6?U5yF@amG+2F`$po5&Dt)e+;)E(kmYXbFc!Jo6iIbHih%zmaTdxVsSjnCAD_%^{&UFG(1n4*z(-B;A zr0i*LqA0OxuKY@z+@d*oy_jIIPiI<0e62!W#K5?7#VFlZJu|bgP5Ld7F~979-+SMF zLTjJCZ6c+A5ZY-^X2MiO6MgT$f_)GilIov(-On!I&F}x4B0Z(N|DwQiFEe{RDhifw zjmc*r`&T+lMO?+RE3CwDb7Pw#H+3F43bGD8GMF`9A;6Rw;)azyGM7U}_>!Dtjn2d_ z)hc`$UKo5uEUDZ2oqpEz*_W2T$U?r5r~74uQAvQLI{ClYIGjs#y#@0E_;_Yg+TLQ( zEn688Mb|dpJhMkhlqfn2?xq2e<5+i>$iqHL+@k<@rRGJTfkE71Ag5J?*aMVa8G_lU zNmt0HZ_bBULR{ei8Eo0C(8G%X4@pOH)boD~j)C-UKE(5Jr^h+KRwBV*5pFykmWQON z?K&jexRi^e#)mMXIv39m{x?JWmpw5c-|EH2gCEz31e0%l+}09>W_7f}sKhQk@aDB~ z{Z&Mo-hWXRGQ7wI!ka5)`ZpDSpM(PUNI&?Qtu$D*goER#a0!Hx9>Sbkq3JEiW~=Dc zzDHL5$#Ya)`;DF1?o@SYwei2+TXd53BS_kaKz5I)5pjY8Q}DJNi}` zAf>~C&|go}Rv{6*&(0a32MwTW(H6WmRpTdy^oDxFQy?x7KRm}IY6+3+b-rLBX$e1E z#t+Yw+z4JJ?#d3n3NH>G$U~~VxO5%0w0W-@FU_E+w4Y;RPI++>VkSWa@JDuW|8HWe z5$T7cG(Q;sq?$TO3wcYv$mZdX#)NsE->4@ELT5oLJ4CZu4N_UdWFSzEneIy9-r;<- zjfBy^b{}&Fwk`44!3V18&lFeh34CRpZaYNo5^mtJyQhh2qy(>guEmEIFlF*t{6{0U zlV3C?cOW$sVS@N&C$<_*E6{QblY;vLd>Lm77&;wS)QNYxG z$}ve^eflaLIk#{ywCr9|2zPrT1;!`LlySGN_h(QwHzd8n5Ad%{0{tv90s8s>@v$&z zf{e_t*zkLgx-I@!t$+3QR!v+o-s=c&h1mBSun2`RL9>?R0tbYDuicNnNGcWj76dkq zcxB&EPVK4MQ5&@rSByzyocM(H9`-u$O^)}dD!kDvW!ogF1$u5=jmX-^%czQRvKVe5 z++?iM@r#K=$l|AxxY_7{Bj?nB*+-ZwO`@gK$2 zjMSqY*vbpl>kB4>*o}tst>VT?3e2@8dpB{lRpaUb(aO>Ue=((h%c_t>8)oEN&7r@v z@agA{Mda7|%#b-Ohg#U{AC4k}qB$4hiKMdN1L8bDeAnR%uzs)T$tTVp73*$@LSZ)0 zzd2mR3P;SQk2rLPw#5WaOTF2)GgsM~D`uXwYvlXVKe`$h=foaef^-VtjlR)*pE0^x zKmpAoP#yGesCp?V+rtT0=%1E!4nQ-g{cZg)BgCJdGG+1GF(u4_SO0%U99V%r?GCg?>hO=ZqKKZ zH|7hj1D7`?2hX4u%?8}F1)#eekexdo-M|?`GKnU5^~#C zrk>sjn20k}DAM?QGErVGctN&+dgaD*lbK6>TFCtyHI-lOKMzLCES@ibI?ha2dyMXX z3WEYZ{lQ4QqBI*`oi7r63Stop8So;d?9G|Y0P!W}*|T>irNzJH$sS?$RFI%%+d1-5 z7Mi6)ePQA@DDN-y-FQpL*w!D(rlVsL@+E^c^4^!o0V!8e2yEB%bJsm z@R{gs@EJ_ryE%VgJF@5W|Laa|2&~2*RgE{ae|nm>+!ep**WHL8D!ICD=TGP${yVz2 zvVCW=%x?6+Xsyhr+wS}OUEGN54!YN_W2#rttV*x|beE3F$NO9>Lat0zk81>XWV*<5(qW-O)BG|TYIa1lNkS6m+CHzVv0ybtm(sK z!Wne?@?RGJ5>Nz+haIjO0F;q`(pFq5q0!s_;oRRd&BX=BYzUFtAlwsqHWEv;>6hVp zweR(R2~_$*CMKHOq5LlfHgSu&WUv?;E;;B6ZRr;G?QbUjSONM1cruS=VS;O(N3ZTl zNzXhAHTol2@>y;4_L-*d;raF%4%~kiE|Eb6P|TUpeYMs4-$${l2Y+q|noaQkq9BS) zX$CQ(?c?kz0c4{MZ4j3Yv)o5t^|`Yz!swYFGAe>u6q&kr|0e^=h_*#!;Ja({>tRfU zT&I9is9|)vuJwRS@XR4crirP5e-Qqq^Y`P47{MWQ9rHX&2M$&h>q|7N4s1R?m}2d#g)tHzwNbEBI0%%TU$nzSvWL+GWNl2~)=g+XT59D}fMtF&Q; zlabe}#Pn+CFb;nX2(|=8`mYSu>}QOb3M|a|+_zbnS;DP8^8e6%vl2fc5PCG5Q=>UU zx~`0sm)_GcOKk2WztHyPO^p5@hS^Wq!wzQ}6pyNEZyzwM&xsSWwHvU}uTJM2th@(* zb5eO%hH)qhg{t(&{B%_Get3-2j?F=_@XIf zGP=n3ckyT2NPx{J{^C)qy(uhn_*s zbV~Py#@Dp1nUtn2hM%h4Kkm*kA~`k9Zt;k%kZ zhJr!6NXbfcAvDm~aoE3S)QvsPkD?UB^4{E&z`Q% zMel4s2QDbUBKYl5W{{amGBJX$xPIe$VLW|Dj<2?Dg>niZbZ72i<#1OWL9>4)c!rMISQm5z8DP zgP|d2Fxcv?cyLj8k86LZJR^5ycm@_V#xDzzv*_*S-+Yz9B?N!cb*S}JeYKoJ?9Rv2 zEpFhjLBisq&0e7QeR+?=!29y4L!i#$D>ChlSum-Yl;2*il?75}0D261Q_sj@0|K6J zDy8Cm)*~NfG&m|ZuDOX*pwYJ?F<@v-wrxC z@K4o8BK>xXOAPhAv$21R-CgRZ;`-C3cEZ*tF1vAhSI;%BrX|T&KDEl`%A-zNV)G%a zH%SRkA$O~?@3tq^K48yqzplfAE_AylTBVYj@mg)u`KK zd<60JGzH~+u~sa z&F*XjreXY6*jKq1&(OrKuHefEzI`3%-jUjDmOLTQLuSs6U(amSQbr#&EP2-=%p4W@#Tw8MP= zpj*Eswm4oEjlH$CVrdezcl`<=$Zif#aVW8RJn>_2?$dUrn}lW3z3QyHO|i=NbTemR zWjE2l_}S=cF6#LeohkXz`5p_Ff{(e~Vg1O)Gl1Q(Q+!iHgQ>z9*?i&TB%uFS5c8Dc z1@Fj};OE-s?q9giru(K)wMZ6geriQ)# zmm;AL1P^P@PNt2$z=x9@9j3dbF^vH9WA)(Wo=Ik}l$sgc z$rbt__d)1`^B3bQO5=lL*>WpMWd{cS%k-7q*|pZ*7uXL*cgn^&SG}G2q<*|Iph4l2 zf$#?)k#7{C2uvxnPGg9fdpa7o}SWqZCYhLNbuBC?cwU6&3N}t9U>OYX+;WY%|4xX5OK z-Mf3+BCgv4uAMiMC|lf7Cupx2X~Hf+1j!ut{hQtSYl4K$1Dd%h{6EQth=hnc#&?XF z$-Xl^DRI{K>_n&EH3{4;)<~A90)(UvB$G>KQTA#vhfcWwMGfWGIOoP^=lv;LE1HO|L)Kx?+U|L_U_seG3d*n8MiUFz`GUx8j|h(8D?t5zf*xT zhu;MuoTc7nvX@(`xdZ2xIxbKOhu(0hRX7UFHsP$tzM300Zv+2FVkU1H3e3-)6gSpx zp?2(~Q34BeoVUG1q0EPje^71Q-yhP6pc^2UfuP=%2G-uvdMb>y^<;g4!dD-sff3 zSlao&$a?d5D!b@ye4pbKDpN@2xiU+UF{gycJZ4rXV?>4wIi5mgmLZul4+oJU<9YHJ zqGXnt%(KXl>Ad^a_x=6e_w)W$KA&^WzW3T|UF%xcUi;o}HS=E%z?)udN|&>_n1|+d zDTpGq7sNmI0ImBE$AGuIEQ;*pZhS+Mh%7_fUis`iWsP{1kEh?Uu(CvZo=?E%(ZI}9 zPW$J1`8zTFx%*E_=iqs9e9rvR!?0`NW@XF^`2s_V*(&1ZI$a(uSNROkt=ryX{f1O| z6=}@nl7G+FzDAsR%WcmJapqfKG~)WkRhc%-h83e7-4~67<=M)gCu@p776fcNsMFgD zWG3ByoBYv}-RpXB`eJverM}{|f6yLn!m3_;RkPcbAYs+JBdV`JEeeZ5l5@ZN}r%rXo`Xw^>El%{e~9J=0? zxsfR?MLa8r(#$*P5IQ}dCv$2(_;VZGi+~Hos~;RxKTmS59foa(q9UDdRVVIcBC0Gw zfqdd9^~P^|#&JJ?Jxa>$-jjXXm$H>;n0Y;I5}}FeG&_|#PW8Wf-AG3B!NmGZm`6=w zg+4`PU*c&JtW!!EK1ayxPxQ*^{lAA3f^g-Z@qhRZIU#^h@#5G%iI5OPm56rdeu3P} z;H^AU)V7oo2f9kV zJGTcrYqSl&$#C_3qGkJL8|FDO65f-jP*hpi?BhA|;nwVLc-@TYAbspxo^_m}iSwSeN79Og$I#b-R>hu;fxU>+#h| zXr^(03Z99KJ#Ay!{LhIK2Po&C%FyZ6a1yiZN8$9!&0P}Rlf+S~wKl5py3^c*{YvGT zZ(r_7Y44>ErTU5Id+~L72z|Vv*>zn)BJjy&GAiJ{-gs!S@`TB;CBuUr_uG;Ha17Wv z)I{p>C9dW)5V_2|B33jJu}$5QIzw-?R_iHAZ&&6gF~%NnbzFS*O`E7omfyc5X{Z6=GNmnr zeUw`N(t)@`EBAklhSh8E`(_S#@dThHM>mUKajQ#gKW=o1N45mwH%)fcp_S^-qGB4} zk}@f%h@mZk7Sn5MR`q=0Eb+H=$;8knhja=?brIRE2F!h*PIgW=Tgd!|FUY4>6`G-v(9O zA1&$}?j02PnY+Hk6QeE&sb zlV{_uD{}7szH7TxaX$7nD=AKM_N?{&!o&56+uk)qy*j5)zmD##xycoOs;tQ9*RIs; z8;;A{X?S9?lt27fZfbLC%D7%`e06_sw`y!N+6nJa>z7|->|vN-HsCjQhyLF1vtSPi zgPh!3mcLhJMu-f7M>15eD&>b!6J$UJTs8edt|}BF5e#4nZmoju14(~+g;{b+ZU5=W7T9@;^^N|Kk zEh!byigMu$T))?Erc8;8#%KlkTSu7-Hda-LF%D+7i{ie83pzwIGp)7{vyK`)^*O)E zhE5y%xIF8+ZU2evb=2BsD%a%+vCn3B%v>QVYmVZ?wHq7cD6-ll+$|G|4^)iY3Db{{ z*w)r+c{EPVuTZ((f~V{h!GF{^33OVkvQs!WpYCk6aERK@`fz7uXweswwftodOngy` z+sd!H0dKi?Srao)s%Q}#cq#x=g6F1wmlnKdTn|%tQwc*T-(F2}YPba?6JlbTzmb85 zqdU|%7XNX94}Gm3hVeO{7DZTw?8i+6HtX_aWuoGIe$$Vn((hfCj{kBb+&49wBCPJ7 zRbkW=b`NELXS=q1i*<;tO#!ZD$?YEbz@y>a9eEi>)}L!y{&N?8dE--vn$q>vDedcP<^JeO6~WzAJH>6X;w>zSWkVS@8CbHyLj^*TJbf{!1ZM zZSTK77`2a%SOJ|6M>6`GRRsDC2v+vk@-8R!mRn=GEu(uK)m2R^kA24W>m`J*Trb*T zaWGlh>2ELEc9Kc;Jd;{pH2HO^4wh%`k5V62Xr7n%H>sQ2Sb4l(``FA$YE9nL&$OPc z;dlLZLQ9dAq2F+avy9>RN}f|)@uL=-mN`$>%DLggI8D5dZ(U09a8A*H!<18<=Ws*n7QjxFc^?Q@JdgbLtB;iPDa2TV z!^+pp%}?CHtq7g-gOuE{=|YM|=;~O8&D+@JV{*e;h0Wp!2(6(9t6Jmm#e@DQs!6@8h#)|^Y2V+?oSS(jmy?`Ng&=stG1d`4POgiH0?aL`FiO5w;uVKk3K3`&vO`VW8WNcNImR5gb4WE z@0!zK&Z1L$`To|^VA+Sh#Pprjo{kE&n(^!VclT=+$K9VDjQF*Otqptl-ZragTa{j$ z3o8zbpmNj|F;{JhQ|Em1aS9*I`_vXI$3FLSCtCj92gyZM z(dSFeDS@(&5!-_$bE2>P{|g&@C;|U|5#i zCQmKQTRY@u*;_I5<^#-g6kps(?H;$Bt6po!z} z0T#g5zelS3JU-6B^xD3x>}1c?N|t4iHeuYso!)FFkccfTymz zEpsl+gDUzVs>e;siDyyU2fI}wD;~;O ze>PU+{1RwadL^3rzh7FhWjAd9I9IWHZSBL>9_Ph7W~BO3!i7_kCIKL_~g@vAi80UGt_>=R)gxLi5Yi+8=K@_W0eYA<*9opbxOssm@ z;mG;3eP>WF^8o#)*wSGYozW_;CEmGfo3#J&Ugv;Lkt7Gf;vtcK^B)Kn*D-}Hs_bVj z;wtlQ&n9)ZXR)9zlVHDnOqEmLQ>*h#C9SPcE7mJ`yvJ_rp~mp`lv7IKezD*A9R%$q zaoDY(AhK>{?$?W1B=$b{y13%E2x{oud!S?VXSwvF5E2gSy5zdLGVT|Pr&HUVj?r8M zLG$9Zkp5#dw;a_hXgT^GW2tF>PqwK}(fu4wkte!s%wHg$itUa)Z)M-3J90U;_xlP) z6Z-=v*K)ipnB^;-lv7+#=g44WC|`)&xE!dd>rR&EokYrfKhNBIrs8^Cady%=ZNZep z2I%E8<*iBn>Yl}E##g4>|9!1zVL!LN{=UbtDK0`&%>Aj`Fo33j@0s~6P9nsC<96zs|WS=e;_=9(DhyRQWLj2F8^ThK)Q)$VS7< zKEA2wfzkEt9>7n92)X*?ZqM$KY5eQ33(0 z^xl!QgbuLtSh2LheL%>7s_nd4cJ%8%nYvw15?VNmioO&SA7c)VkVqZbidO)FHC87X z7>}-1O3`Ag$X^rKtm~}Ho5W8elP9MkphVL}5)A_ZCWV8eV4OVty>hM>NFuSEs~z+(FNBlj#9lqJYsf)h;(xb%oR>=*Rg=`e%D>%H+;@xGl!sf(l0wtzEYO5 z?GyFJNw=Vju*U;RT*Urprx^Si1^KOpI+^Efi!R;ebYEt4G{Dv#aovtyPL+n<@`SF# z5b^i#hRK2dGLTWOVgx^tGCC$CNdecB44Onwx60MkkLIQpPvTwCRlco%UT$w38n<1b z+I@i}xiO3jNZQ$HABLpVho+>@BKD>-dj5hywAcp2JM{YIXk#lXk_O;^zCwRuuswxP zS4p;jF_(Bk+!j0WqkBx;CXjr(G{8(XZtNM)w7bSrZ2lR=keAbxRspu64sm18Io`uOcD( z1Fj{9iz+(e#Oi~ygjjE4{Ai`Ta4(q@$+P-MTI^1%3bh<@a?#JUh0jE7^w^`(h(}MF zq(Q<)s5x6AcF9NHJFt+|AhuHq)IWPelJ*Au$0WxN#Jiq4LkY$k(Z`cnQ%fUr3YiWj zRkpJ^OK^4tw_TN|9x=Ejrw0FW4t8$!cIsxNR@_B0sVF%znP1|Y(Qt$^Od*-EPmF}^ zOlNbQ!eLEu6DsYFXWJ!K72w__r|!;I{gCYuOYd1nBw(-;UKqiWJ5C>jNI4UAJ$$PA z8Prj4DRD+SPLEm1(Q{h{CPy$D~ zLsFbiY`WY%_75{ClwOppf1%blyXZlCy0w3EQYF{^{pm^DezrStL-=b4F z6G?%D=9PDFS%?3;dSz!$s2WMxl^osTxS zR@Wnq9y;`6*OWp$jrzxPEVr{lf6x~T>(cF+wDR;dJ0KnwvM8Vp-gWE0mx;6AA6Q|d z$|6GsE8~RZ&aqzA90SP;eSrOe@brI z$Mf;JqdHSc_)so`sEILRbt_8C^IB=$?~8*7&4n&@3#k2cnC0aJ0q~-T#)dd`n-Bkm zE?TQ|#mW&CoZm#;VW6w<4{SMyEJYsKi^<})kY&8spvLeR7LS)?xf?q&kB=h4lY@=ybbC$@=npA5whuV>l|qnhDJonU#xp| zzS0*v=A-b|{BYoWCAfWp!0Pkxn)Tr?CMEUbSd&Es0pH!?mnWfzuHCRKplDD#am72~ z=D&J3u@_G~$<2%T{>UJv`$Fe$xuK3LNC+f}qfXm?u@sq%EN3YaGfFthze1QgGD1eg zTE2n!s?NrO_}6W8p2?$bEge3AI5v}N^KpUp-zDaD@;CEeQxU53eBRoN=yvH}Tbd$+ z^M`QH+u7E2J#<`bXyb0_wf?^9<(i!a$p?>{ueZk`2Kr4l0p5;zb}&P(P|QI+nB}y4 zXYhBmpot90Y`*7}^p6o6Uz-9mNX>s)K0@3<^ah%tZ!f}Aland^=v`WqiRR8jsoI$5 z9y9tam(2S4P^%vFDxM~i4XMs;%eD(FzK-!6aE1%-c zfg@4Z_f9V?;?)9hGqzFbVk?a_OCN}r&$QPOn|32!3R01G!Xlf0qN=d^_D#d5rkckw z04EJ`Z8vMP4O;9OM#sqUYV%Uabu`CKjmF)|jZcdP?d_rmLV6<8nA`0QpFA6sbxs{y z|5O0Q^Ezo13yRu`I0JIE?<$@vo(|oTlCkTt&|?%5X%L)$kW_FOi52*D6#4OsF?-6X3#P26_HL_v|v=f?z0LR!JsnGwrBY|Y|`rROx$s+GPI)t@RL zf03R&&jsFFG}J`jbA|}|w$OG=WwOwr*sFR@#YSS;Um$rtg|s_I5&@C>A6hQ#tf*2* zE#JFKbL1>ld&bC785c|Cwg6ZGxNHadmYj`PCW%8sG>Ke4 zc8vRy-C=eJw_i*pP$IM7qv1eXs*X#noq{lMizBA#JgFrqLAGqaols1P8zbj9(W`2^ zePr0QnWn6L{@4XPXwDn0dVn8;@4^RuVoFFjyoqwBvCJsTKXM^tMP_|&Y)BZ!AYs^D z`K<=RMKDcCx83OF>$6c4n%*{FFV|IcS$HRv4)Dcl2xKXs!OBp8sE)ZAHv+gQvgI2b z({miRv`(19Rw_k|zVS=;a<= z?aqoJ16#6qIuE8VIR**t)g3pSaDNGu;3HHKr4mdw!RIo5CIUHArP(*T!z6MY} z`QylQmdM|b+!%;Rh5%D)a+(tPm!l*MCkqUrOsG07=nAUl^1=_-=2GKmIf78P=IyqR z;?LvK4ZKrMo;yy>k}t5_^4tgGG$6WC;BL9xy z0@j(22Y7?)Q+yb%p)D0Mc~Cz0MfJgo-^Mfb>-4%nX+SscT(a9m3t=P?dy%6;?zRto zMNJq19X4h2xMmueRKq_)q&Sx9ms9bbvuqHnM#!kC-5-r#S|fp$i6zLg00ZVMS^J)F zx$;uGi|~A`XR)pZ$q$Je*V5f9us?#48OjGlriM|+{u=*|*2=cVmwGLX`758a^}@BA zZqt~0fcYqO@%?K!NVx!}BLwD&O?XioGaT$C#&LbFs;ie})PFkV;>EZ5b+8x8GL$&* zCpg&0AxBDU>!njVKN1E#JX(d@rBP2Prp6ME_Mud46&r6eqpyLJK8;m!Sx}lmm&iUu zvM+#H?XO+dc>-R-*HOTb_lhCmIE#wAjT1YK^GPYpq#RYZP0_qL%Y_7t6THDtqumg{ zI&#LP=T=x`@VsEp*Bp4w^bP-+WM_|stPLQKlM=J~6$LM9OO^lW~!R6Dq)tz2E zCDD@y$6Eb^sEM693sWQ`k}Wp%H{ZipNXLwfPn#3(@I|EGUc42QBE96#>Rg?G5&cYT zX>Jg>|97^Aw6_@(I}Bv3_GQ8Awo)q(Rw*EcCT#c!lM-ODUqSp!1F)WNAr+mzv47fK}b*)W2kq=Wp|9L^KVcjSYBpz9^9du#Pa zo9%Lzs*V%zsKB<@Sw$q&lVlLqbwsiG41O(y{Ko^&v)COD{hG0p^*%%f9SLWVSg*xL zj4Gg@+m7_c8ip)moc;OFy`Rl4+=v1A&XP$<*H+m)hC2x@lt7a>cdIb2$ z@t=3>LqUh^?3%K{caDu$@`eyZrq0ORbr-e`PM6qxc!+*!2i(V8tE63Qh_t8@T44tG zJb6fFupgIPI}IUOlOv{Ck8AW5%%v2*JJRl>)rsFmH)ERp&!EVrV6e5yx$&k*!S85}ivgn*(Ssfn=8|-TJA>1xROCUjRp1uE)dtToCWQ3k z+!c#Ecn+zjG~F)YV%zsg6;UylbIM!3kms#7l25$+tGiHp$pr`*)L@pM&y@7LCq!k< zTIZF47d-}NM>dAH8~xuPO3YfFY>OQr!j zvh=8ldnf~Gt1-K+n?{^lTgtQY#&g5Z>|`lmHc>$H-4?n(TI2k%Ah{@t6z+w2hJ((% zG&k42MT^UOHistR+(F;hFa9e439JaBFf0D3B8QQ9Dqvo`bi;N! zRU%pgf0I0{q{juV7D%~v9Cy#yH zop$F%Mq9`Tg)Kz>OxL zlm2>^^off9kzpjz{R|FN(Utud9595+8uy)n;yYW?LRL)q<#gHt8TH|Z4Ph7N5YMmu z2YY#f_g=X*RYNimm;vioaTYcQCKtx}Wd*E1s0NZ?*(bqEc)k^L5=wyqDzs3%Stw48 zhuI*7m)e7vh8?P}{6JKsgztGTrX!zV0XmY&Bv=N&J)?WI)YXJ{v5UO!z z@`P3AEii9!)?OV8<<-gW^4WwZHb7|IV-~4X}|oH^5XX zlME)wy^d635U_IDMl_p4!>^~IeT#WJ!`Wjy2Jv*L&b%E9J5bZ`tcMyX1IdGNatEILe6@OuLD8B|wY~Jm&6+ls%74;9HUWwtYRNFG<`L0e{xCF*&|S~BnhXf7-am)i-%s)%Qnj;BG0D$5ZGW0h1F6*{U*N*_OryLaDwn4V|~9G<}D?VvQ`i#3P%H|9Vo69ol5Z$ zh0GWN?f)sCz9PGuXUboDm0n$b+CTx_Mu*!<=)cxD?@a&Qqv4!21TPptGUOlcm#sB@ zf8+W|i3gVf9*M8Ya|6?!2bAE>(r?tq*grhS#lGEHNV@+wBqd_Mpg2amB>p2U&2vt9f2Po10he^44-JlK3v*eE6mOy7dSfHOYGYO4WK z&;V;XfYzig*?7zJuuD42rAPuUI7J$~6@eN!WbU!Q%k!*dztfvB6G5A!<L0lIEiHlMeMv2V>r<`T9m{<;mY-L`9n^Cs2~7JosUv&sO00 zFZ+6uXL(d{T$uxVaG5^CnrWKwbH}2GKak(T5wJK;Kyvz6l~`6zV?P(!l=WPx*dMmN zs99~9_CDsMGi=FJnzny>lUcuHT!HVn8m=Y3`_W+VZAC*EF(!j5I!8d!<-__J*Q(Zx2bNiq`30)^)vp@`js5B zbdWGzM%UeS9Ft+q>Da$G$Zy2ts$VKz33ubkfDgG~`2JOJMasw|7^}-!gLnx?=Oma= zhW><|z@jVW;;l$=bY187oq638PUTnj?N;9OPT$uNVvW&V%Imi{W=?8}gly9%(+w2< z%)1>KCt`eUsNlJVham*4uz7{W(?=~_7mRfy(KI{6+-@&L8)?()gBg}(TIn5MK9 zZkVa4u=fA4iA((c;GL)bzPL-;V)c3AK_&v|JONRrXQt%23QBjzDRE8r`-GOQ``$GI zo?AV4A26=a{SBoNEZ zV$;=LK{aTnFurj$2=%d4e@@6G_^Lp?JZq5&{~TN*ILntvvN(zSDkV<|BPudL&)}xq z#d2Ex!1qivz=Q1ejXtI+y^x#C5vS!UwLPdDNt%w~hc`e;u+51{3M4IyB!MOxtvC2= ztMVmbg-iQNGS-Y}m$-)0$2BPvG`_NeiXt?R9+|b5oxa2!3|3#u!OMOnEBdp23*k^9 zp~#*;((70%@;OVEU>`Mfo>(s)4UC@+t?!%>h%0a{8tSqS#@Q6KTbrM2zb|90|0S1g zpy{uY4H*<@z##BKdiL#>3cx#3QsSi5V`=q-?76Ufg_kw-Dbc}YvpOGjV|q`$fIHwI zfC4SC%qlfAMm%pklgt05@04R5}1^aR@8l7yEOv4;dK-hUAOMIoPmNY-l09t7@A zs*z$Th*VP+M)_;+)cQQmI8K9g?oO>#)Hj4|M`M@<-f%Ll6>|-v#Z-S`&lSUShIwinr5pb4HKrgsU7UR4W;l=`@iomTxJr(T zkBI{pw!NQ)Xu(p*|E9h- zrX@c5+ceZF;$i-4K0)*{3-H@k`jYTU)+&pC2K4U?I^198+JDjdr34@BOa`LhVLob@}< zmNQqAfyP}Zo2cF>=SpNBIya8GoG-)a28)lkk^y9IPYoKKMGcW_z0a>LZ|oBrC>1x$ z-;1%5$gxY7lr=}#AgtbmQ>&VJ5m%-Dp+xY`9?db3C?H9LJyLq*7l>}%`5p)UyP%@4 z8hDUzS`WAS=`{~7!oI(bq2HC=YyyKI$^uPpv;R}K;GN;8OuC>bh!Nb+rk65V zd9vlM3{2ZmmY=>-;}#Aby$}W>3Z)0iDMdSE&~!)RFCTxUegPrT`H%D5U-LW1>)h47 z@l8};piF@dCvGO_|4ak%hG;_eR_aeN+T5{%9C(V0H1N=m909_g0^F{AYP^ z9DmssgbT2ItMLRfKn?lbFTZ_zqE2I*WGVaFY?Jf(XLCKy61o*;L=DayjmmyP$a50b zxqL?k^^3PRCKB@P;k|X0TPVOx`u%z;TsFwAupB`eDiz)@V`mC%@@EQi z(1m4%RiO;+RPoiGs7Zz6Z zfCm~&Cr$P!-_b4~Q#?sjd(-->SvvnX{PXAKt%hIjDw7m)lUp(!(i~Z^fS3KRh(TU{ z(E2Ly$5Z}mR78x!jW!TT`8^r^}b63drZYxOSW@%>^J5SMqY zvVAqtK=Z`zdSq$eN#X>!eQ_mMni9#@*fiKeNzgo21OhP27#B)V9Oa_gVxVJ{luy?m zVx(b6uKz8uF{UM+x-J7pey#rmNnitZi+JY6vKul*nC)ERfrU75=T z>i$Hlzf#vI;y@1?=@A>rkY|2|vgf%E0c*dGLSnDze1D(QHko&QjuC8F;3-d(NB>P@ z7g2xIgiO}@dYp|G|MT}eby!J4m@As|0MnzFNpK!QiGSrW%WE)Z zBcGG%%DIru6tUMiDr~)8K+0dLCt%&Dje-P5pN6D_mG2=k?NIW&=0k*H8Uu}khorE2 zFHb7o88t24<>Gn7bo84TLGB8b8|=ho`1=tFE+>)Se}ftMmk!dl>+Y7keM(0eu1Jx$-e%*;%nFc@CYCK(4~O;hswWWrX7+`cGeM7oejG7{l!x~<0%j0 zS+*k!@74;{(DJr8ARRkiuq?-2{N)0-GLENVW&B-GHHX4)XOB4dUBK@B&S=B_wS-K2 zR&CI2J>|cI`e80|JPRxbc_tOdW`Wo3*f-$WQN{exrbXQ7n*XQyXVv|pg#yF-3!$tP z)QInZ05fDAxEh}x2QnF5V}mrx^y`$~S{xJUdSzDlgV9Q6DR4h!QJMra6NQtK5G}fs z_L4@QWSnUj3vexwMiX?2hg%`m%khdk!;Q83jUr{M{5JvgS81Y8^zo+q|K+ZUIQp-5 zSIA!0v1C-2kfiBiaB;hT;m1UOPhdZ}H+JwQe3Zdp7l zf8)-{>BGzDljp$sQsGjt>?2k(X8Om7!vgdL90_jxn0&=kUuyRMv0iP#sy~WvKFA@N zsNa8oIbUJ7f#TrmMuu)Og%L*J1)JJnTY>;$_wdA0-Qun+2TYpDu^f#2cMpNsBxUI!$ zLB8n_(dk6v^<#2zK{Ji4=Q8P+4klEIjz(;e01X(GeqZ=`KfkQrN10-ZNeW@>qIPJw zoxQg-Hv`40c$$)TQfesMsj+)UJ5WK>vbEpA`|Osnf|Qe@EhYWtg-1`Vg0cPqtjM%s z33v9j#6ciusDHcRm+q{byL@65OV{n1>Dvda^=V5hJ{e`-j`BoCS!Y3UffVlljyKz_ z(51vB(Vl7w-rxO{I1{`FT9Dhc?_R+U6)#O1y)lE}DTl5{E#+>A$6Fd>1Zk~=K5M&n zmzIhjLGb_N8Xn7x=d)s9@}MuR+&-j5i{i&AoM9HNg#`kR;ocP7ScBzuez;MXf7$KE zdL^*?l`9DRK&?+)!ZDF+#g23uhm;QcV0_t+MFeu%5=X&if01h|xBIF??-_UiFC!Za zZu;TMmgb--?~}NnNQX2e+2oL9Pyb7U_^uqe9`BV(ySDuv4Il!0I#riC-{|{%EZKQO zeXNywqtB&&dsmi|xp_6{u1bpcUH$E&{i1SfM^$t7zAX2z{cguT23Ha?7R!HO>jem? zBhQS^)5G;qm2_pS*&C=A6SHYKK90=K=v-bXe!MiMnazQG%#BCu#l4loh(`6n1zFJe zo<-pLvZl)U9rV*nO~~&+mE$Z2`NRdPaOD5X>S=xAKCB-bd>AEZcIanUAONwzb;w1VW26{kLr zNP!nVUq&8;fz~$ckG?fNoCl{E<$hM6*uYU__0Bxjr#&RKJq)o}y$D+3M@Sue@-D+9 zrc>EAoiYb%~gGkK|0$3410FB4gft1F}y47chpZOr~ zzaj&sV*VL-{eA(524e?vpm}dbH?LKCc`GeP_jtR{Qz5ObI^=Y_$~Bo2V}U`tGGG0( zmXG2R^vw;F3A1nE<F4nPD-rezfvj@yH7b8 zIjw(xV00n&-nb#XvGXsW7Y)}bz>T}Jtvabqa~^)Bg)efe0GEp zB#h#twAjw3jrlX~_w7dD!$&v$iJd{j#J1X+7+QCiq!ebpF;WDD?O=r`NnvOYInV`_ zH2#d$x`xo}2h!o?K_7)fXe}jDRs8hX%EU8Op#n!!hjOU z>M9W5G2bc}s)a>m)kTMUQw|wVKTp(8>iRt7q4-Gwg-4Ny#0Ym zdR@;u4O|ipLDf0j58tcTlEyIb<~UT6*im1k_vH&n2vItmA`B8oOYfqXt zW$I1yl<~EH;EUri8VEsA`K2QTpNkJY30hP9FXoo&EG-n?%qthG(W1j@J317{wg1qL zyi@S?eV+mU|15E<^cVSdLXtRdn4j_;oBv{1vR?xibKJd?@ZgFddn|_f^3zB1XOQLa zB7rn(42VTQAMZ$oJp^AN^9@}dIQ=k)cpKhhg)e>B-nQJWYufjpK{&`Ixu^Z$J2Ch( zGt9#g-YX6mT-ZUFFJBZX$4nM0=F{C~?{5iuZ7LE-$Z(V(VyVwR@6RI+T%X>8Po{0#g9d$Ok%2tbM;ReIKR6%}ISmskyz znMl1?2I}PJ@8QKZ22SlnyfC|k(TrnOdr7S;qPap|Yt{-xt72-cFnzK{4^3O6+k zpm`&`^uP_)A>@_`L#oaG6i(_F38JTQ%KuV62CH2gdm}wnl*mf&b4A`?`QTE9d2&;a zD&%z@@Ohfhr7M1)f4qOEeUhIMmiKE*`#I&%04*@PO<4I-eT1sZ?il&)i(zCqhmgLI zRcUxXj3eu&Q9KJ!wVx^M_rOSg?Q46~flf0yNk!Pv_-7lTp+7VxKCGn9u%JpN1>HaE zwYPJUVpB1qV#IIN4isf={=@7|M#ov{hX(W$58))FKy(pBEoCtn_PabBjdcU_sXj%H zzfBVAdd>iId~dTL(D7pB?HoQD{NTRs_UX9F@Kj7|lXjmpIkMUH-#!|?VgEEi%OX3_=m%%90(kM?@()06 z8ECy6Sq3sU5{p-jk98-t5L_}?p~ktOV-mnJ)}4)hPWMBl<)e!Q2JLr)RMnR}KM%u2 zX+c^eC0X*2+5tQNK0QWNDvS@6RcLG%b_u9k={FLSNeBugzTf051d&y{pulmE#QiXb zJDrOZ3885lNwqanQXGd_{@gev_+w;6MzF5>^&a_bIHK)DVRev(Pt?WC>Ldq%dk;pW zY*r?ly!Dkbid zfs7F>Gyhmn0qAB7$bmPs?Z`2sWky{@CEelM+VvO6aW^gSIpC(k`INDAA6 zh(UldrZ8d%HNgm2vKDRXI#__G2HLA~`CNxRYZ*ABfeWQ?-ME~)g^s{x{R_V>>5uN( zFQ!sf!n5-6N+pPueLYF7(GwH0df3qYh{vpHTb{^H>I}7Q7G!TNgFEXcoOd)P^Q8eP zfg0|-0;v-dzV)k*tS;b^hT87oDLvhP7L1KliY=APUsj2(y$W4z6_Z~mux1xEX9ss= zv6Dv{Z|zA5E6J=VMsb^`3%nbJUb(Ts-~}PH#}`3h9O3_pIbjfNA-Zo>z4#W|YwN`5KItbzdX6pbkB=+XLh`HUYLnAxP!qRs zV!O$t97(_xBTM(x?i{C;)4~4O>`~e5f9;53C&>jfpYjV8eQ2nUMJ^Hi03V-o5Bv4+ctB(*~v;Gzrs~vnaOdeUMYv9P*!7m5xUR|5iq6Xl> z64Jn$AygzAh*x^!_citk{O%{(lHUbVU}WD}d0}Oxbl<`Ct0S)m?ezK|8#w5 zh$_ENAw!H5+X2@942uP!4-QmxiS%LONrg>=@1{UUAjKLY)J!-bb7Ag~g-`)oi3&a% zXjqwy4ct3g{kFF?Ykq23cDrY{7&cR52#5cJ6}PaZr7z?I&xDczDwGQ)PRy-sE>XWS zuJQMtYyY>#8hb_ur9@Yco4sE82%;9ligu!pEDv#7ET@(ru~&1;&cM2hbZ3l)GnkZY zZTvDZsfbjwEJ%}>Ra7QyNV6QmWQLmCnl1)rgTgx9F*ghW&jLoB3sx;=%g!RLY(bfZ z7@)SF(>M%WT4F)>LjOHb8KUn=%(3zG&q~mHrhO88F%SdRMX?)vYP%vU!lR^Byhvs+yDcLgz*_?+{T!cPBBK$~N9-mU7#+(ZWAfE{V? zBZL0o|JJL5?`Qg6ec(t+Fe|*)=D4zMu;Z#9xbsE&6SA2GoA4ZeK?t1S)aAS)uD4ih zVSNxhV(M|tGdkg1u5tHzWl5L_Cq6xcMEDh?S_-XKGl!10 zdmaP(!JHmT7W5gzUaqLRnD*EofXUbw;I-5w|wh@;r7}3C~b)-8K?f(fBWXX(mUSrmQu1~*=;raK6+&*)falA z$aWTh%UF!YQ@|oePYEnUN^jTH$09ixZn<2WR;1Y9K78|@Fg+B=?l^m4}e zS_UIn45X^WU%)ZR0fcmlPK>(n`XCuXrSq zALMiMd5yb9l_F*3*3{zfz`?eSKdr!4bC(tBjsa`$u*8S5)9^09mv3rQXTqCaRYaZ9 z-&p6ge!r3N1C<8ZF9|%#WwthReJEY)kf^FQi- z=1a%9f?Ut`r(n@{U}uSC)0?lU(#&=|EYer!1uS+CY$WkH>sU4=uo&Ezkzoe z=NUC|dd)2!W)ID!OS8^ip!j-eCpi4!Sr8w;xw^Pmy8py)(9FWZeZbI7>V$C3X{i&7 z7G5Jm#L1d}284?ExsnB^Oh4IJm+J=qFUAeS?*dyk=61>OH7 zxJho+?rzTKCBEW*0mdIX&oVNLl#6R0{d%0#)3UVXq91LJ%l*1#G-=MyKe_s7a8$_P zT^3>3CdtHJc=gGdD!+spjxnzM$5ihlekzy<%)5`zwX|F}jQ>^cy^N2qNRcfwvJf(C z@3$HsSRL@G+xoNZU1yM5zEbbqVdL=0+oA?PV}Iy0=#3Y$C|+~J$2qMP@7MdME;)VL zQyaf_eY{`4xP0btWc#3ELwG7nDE?tkMa6(U>y~L<<=E6p6%@KFod%ue;NexLT2_ml z5A9xg-{DJx_lI0p>f3$tc0zZie$IQ#8CGtM85e&a*zR?>Zur0G`toq7!vF0vV`Ql; zNhMhlMM5drnNo=CTXuzH7a{A6Hm#^EAtc$Ck$sG=7sR?Pgsc^>nIU^|T z&)#qC``I(KMN&|K)wazNqpLwT=hH*jjyzT9SOA6##h~l&-Pkqt zD&F+jlbjr-N=@3p`GQyGIh z%)F*Um!^ESp*qvT%lnpYs_j31OHlCd&$A!mYFrGS9N{jwr#uTMi$LL9b6NBy`-WRM z1|@+iV+C*abq?b;#t6f>O(NsR);zpeO1(W5zPXi66@q`&(0{#b+EvM`6^Df1`HR^2 zQpUR@?^7!)#t21|ZtWLollBS2La@D9Z`UHcFaoF3=NX^!=!;$cGz6z8F09O?(XeJv z)B4a64oXj1FLPBr zhIkqKIo7q_txHjOcoL>t)6^L)H9#G{$tcqgq@I_@DA(qeSZa8d|M3MuFyYr0`U1_H&jdS8_c2r|+-yBSEDtjyGpm zp0(2C@HDsYvGMoJr7Fz5`%nD|;%-@kH&SBWc0?;`l3Rh5jFT@n1j>w!n7|i16Fxee z-h(ZLY}_^}HmVM^nx^LjyS(3$nf=_%xrZh*KdGBN+5@dV2^>553_8Y|?7kMkb2n_` zmIMpQpEl1}oTR3~>q2G=(c=~Fo;ZTp;I5nElRuFit0R2xZsDYC>IiPguSGC>|8&ER ztsdp!dB%#&K^Vt}n>@W$Pw%|4N4Q8}>r>Bzua`cNJM<>`4;+IEjG!oORyr}zN}Fqj zSHHU^gDA}liZ`ycDX>FBm%SgZf*Q&NOUldtQkXURf=Rf4tyFC%S9)wd1uH2oZdT@Fpcfb64O+tAonJ+M-q=|9QPhbP_}AFzHnK%^o#UbJP9b_=y=f_^bt~r6{n! zYPng*2ZT5!ya?}_AKammar}(d1_5``k5>MY5)^6}7#Lq@_gc9TSbi}uS#5KqwK{m} z{H03n^e{rl&Nq)fmjzRRV!&VT_*GbT?JefmTv(Q30?ekc{yN)~v(7VH{w2<*&FnA<<+~|AZv4a$% z>6qT}36Azcwwi*c1Uc2wJbFOs6l3#PBB(9#~$i;x1>e}L9eh|e}UX$*Q-AeUvm$3!|3faoOT~aO9CPP3%PszNcH(?APa* z#Tq1C(MM2WCeJhNkk~Kc&;=W7!X@IRNjG&b6`#S7ROgI?_v_ygW5Eir)W-9W4i{6! zLjIt9oV8Zjof>g^Tk>iC7CLIT!@_=Ut&RE9YSYyHpAhMnxY_f)wuBhAG$O;hLu56% zw`TKQicndN5#phn4v*esj2(i!hSQRcGU!xJ9PCH?#A&e@XrGPtU_ay?C|W5yAU33<^E1?27T~S< zaKkenb*kBw1nm8BG`dg?Zu67OFmB0y>)hc_f#0Q-*^7##{k=Pc?2=m$kL-fp;18TN z+)RwDJQ>m%78+7J)8IBll$yq65T|jlJtLh?$F2A&Y!;oNYj3J*E!jSDzQ?S|&G(*m zCwgjqq(JiTvwl=wPf1qCz294}n6Vs&ZA7ZhdGQz7Zmf_aWCx{LBca^`;kzpD??8O0 z!a)>&mm+4gLG*J#Rv0I$`5XL-0mcVPOaZG58hdE}%w6=>56$X^Cp#sV^V(S6yN_X2 zVPghv^Hz^k4`qJpZgmGpcKrkWmR|maHsAWEuSokct(}z|lO9uSL`pPHO%m>10D7tm zmmc+ZF)j4y+GW1wG0wCo<#ChcYm21`zpc4;(7(xy^smayubkVf5hg*X=C(76B-0xNIe06QEYK_4SJi2OVwqt-VPtNyEEFYW7Ew}Mz34oc3f%aoHUf3dsK?Y$@ zkI(*79s_8!Dow3wKo48%W?rA+0T6HJ~(?Gfuv;LkWH~7|hpV(z8lN zE#&Rg#m-PvaWd#Kd9V4*LYHJ za?wYWlx;B3%65Pok{-QdR53K_N3h%^S;ftCu;u_&-uMU!ZyOb-mvz}4=`T2%`p(=5 z`G=VT2wlTV+jIm#c+d5ad~C*7XraV<(FWnNd2WtKnZH-!jt}{G?Eqc?GP4d$wrSyx zFZg?Skc&NN0(z(otuXBE)N)*?vP)e33l_@P3cSj)ohG~ne$k_9tBh)AJP74<8P^Yo zX|)9jwsWodwd!dh=GJi4?AqkHhNVUxq{M}64G)yEx)TTu&0)?spcQmree{z z2E+n;`%=AWVPT;*^FPanvqPm!D#vODmdF;8zC84~5!WqVT%~3rYRhBN)1)Gh_%Q_^SD*mpUm8J5d-t5EJOP0#&gDkGZeDC(2 znNJ%PQjzpX%X?Fr;zcRYcR^*b)(lf}CDPXwdWnZk^UIovJyRN;jT`e8?xMX*BlQLD z%1n6~q#ZQ`8g9NR^rGC?zoIVZTPz`}D4k0E!ELn!t^JCEs_FuqetfHNJbND`ufVs) z0pFS%zEmdSnhfzdbxl*gvzL6Q;b6idJ|-jfgWCOE3T%Jb^+ z8~n8gMSRj%gBtOPu`4WLRrMP(eRtd0Wxl*pFb}aQq~uwvU#nB`F9fuy>eWa3agL7*GYgJN|t!-(#ITQb?+1suSlo|?=?zRw;O!3Kp$K=y)ldq)6`8UpK3Puwm(hTR7!nizi#c%*Q?OxG9kp2SUdHUo z0LTudKS2dhNL|=&xKohEa~43#Jr9{a8ET9uTQnRwg2VdxiPPE_bpvgK%DDr2EZbCQ zPs7?&Eusm1H8TNeA&t(VgoJFer0$=|B45wM8u&$kYG0}qt;jR%`Y`o)U#d_7sOmjJ zywbKR7#cM2l_7!u->)nKjg$#_x!Hj!3sfP)I(jQb{fE`}=M^t-VSDkBsMvH!_ZTKt zgY+F0fUVN|1uaAkw*Jd1w2(2L_<>v?aDpdE0}Q*C2uU`or?oK7MzZdS=6btCu}Ux5 zs;;l*3f(iBvOeZD_FgaUyT%o{n`!ECd+aEMgIT+`s3v_I=e4{X!K+tv{tSexL(*y) z-F|ky^SV^mLBn~%;Oaop*3F-b@8{h+=SqnbOZsbXig(+*l6_k@#oxNKa&WPH@uqbz z-N2U6*EpCx({EIf>g7H6jN!R|@D5?vdxo>+XyR`PwiH%5f%M0axbMm98sCH3l-n*V z>pR~5=srl=`e!hJ`1zLMunj_CW7S^QyJ%k1@QISyT|;YAwLL9SAGouSn~^7q@2HU( zuUy4DyXURW&P}I4aoB?_ZlwX6rdlW!E4MB|+i#DmTyI_Nt2TO17C)$7s^%R^rbRE7 zIa3S3FW#{7L>v!V9pV>45_|Uf-_~Mf^1b3 z?^?NHB{lC}l%Z-*SuVFK0;Z;g*H;uq1sBz4huMWR6t>alj48Q5Qt??^SreINJUF`* zT<=9u^acWs4V88S!2|TaGlniwwUnUp(0X#O92xxcii*OYy>4#YMC?|wP)B`0rvabp zB~O1pDW;II5!r9mh9_85cjW=N_hQ;7c$|q<@l4T7dEr<%64gw=?B5}8L}eZ@0_xZz z3?o*4rJmsbZeB8+>%~I4yLY6>I-s&Lzo-N4z=DmcmPsnHp4KUlOS{dt3sNu6p;lX` z+HjKJoEm=wdJhp@+{Gt?2fzHdQ^)iY!0#k(414n$v=oJD&#(hO4wH@@JG53{zYpIoa)kuNy zYLoDd_tSu6nlTL(&(_wzpY(YCk;=KX zn3{mN;eZCK_A&RdF;7pW9!1qbMmtc`NOWPra@@C))S0nsY&Zh>9{+ffVS-Q1yV$*r z+V=&u_hqW&Vi~ zT2Kzo{i=@D4V%xKs!m_NOU6$HMj6TZgB||q#HKh?v5~DSY88JetoYWF)Z8hQN;y zU0*Lm*Y|%3QJxk7I&qGcg_~CSRZ)tv@ec!dvT0Z|QA>HtNj0Os#-g zI)?gc1O3|FY`y*ulx(plCiy?(AN@E4kz*{ii$C$gZjJ43x5 zbMj@sRz>NELDWu0Jn!-1Hs7yX#d1;Ea$@+>s=xg>G-W(_A}1cUS!f zGadc!Hadq0S1>_sD0#f708mA~Sa?B&#-TV{|F*cjBT1OzUP1X@CU2pX8!{yb?rOAF z*n#hcOLj)8%5JwlsWR!>m1oyA-bZ%pK5Y9zkDk&!ifmsl1vJVR0w7;ABt`DOM0%XR z{4-nJCYO%g6cvz}u=RP1-xFAODCX(J;Aol$N_*(igt}%-zM@Wy0UxM3#Nv-pGqNrQO1rO0V`p_UfS1w_W))^rW zUhC+2(%*dP_i57YKInS|U6&zWaC_8st*QM0&g>)_>zyCob%-vcrPls0Eg&G;H*ruk zQ2)S_mN3RaD=vCY<;FQUB`B0u35b{GB+oy7*uciZ#KKrzF6=EKW_ z$47j@U1eQ5Eu=MzNXTJR-lu;Xcf(gdLA(6>)e*+h71 z*EuD0-s#a|Eh8W>fhP^}6o2qe9Pg2p>fN;%ZF6i~AzP!c9e~&y{-dd(kF>Nd6&p(+ zPAQwMDnU2trhW4zlmJI#brIks*k$hQ&IxBF1&@t72CgPKxLEvvFPD5An z<-a}%7llrwm!yk_)Ok!xwZ;7O9i$U?NFi$;gV`~t9vT~O7VjEwt2-%|E33zWYEwwV z`E=rLYvdpLj3RXcWfMf;8$ib8uFfFMYe2EqT(q8ESqs0vO6fAWR@mo@zOaXs#QKe| z6o{YSwvy;BUm_BI$ZxZ1!5KM`FIwQnf%iXM`e@u*^GxRDM)dPQ78|0J&DO+&Eklqfv+V$CtVjeu96TV zxB)I(V!ZpQU2iy0;vDU-_w@K0QpT^V&aa(U*>*BNLF2@y!d^;d2S`4g&>9%*?l6Im z&W^1GNhfp%8=49X=9&|Arv9g{3)>)S}lnT-Ynv)CvAM5c=g2 z53@N%?zyIL@qNgrUfJc-oY)p-!xvDnQlWO9vk=y{Q72Hf6C7?lNtvg(PA75Vr=H46 znzL0AA0tiH^A)#q);;_(OkC<~90NvW1IUS!5i*GuAOlhpi~vOGT8}U8Jvdst;^_eW zmvQV%CmHIeuSfEXey5DG-M)7Zs7a9q_lUp!%DG!TQ*DD4YAHX^+N~ug@jf>r$@Ka@ zK`1|Czq2O3((|kV!YMf^hfJ4NpDi_jA4UoTp_&A15oqQFq&o?H8;FMOT{P#~8y(lY zx0$iG1JM^x+%GlO48I^3cNp5q$@DF}!{Y@v^lO(?)VGHawxFJFq0NMB0t6pdN3BGLACTE{vOLN`%y>bbp)xJ*xAV z6FtEc94ky{#KpM|D1CQL8Mp;RgMoqq=BWj;<_pq@+uj)<2wcPE6nsd1Fbh7b;qUJY zI4WQ1_q2T8@z*=PX)w(S7jKQoJZl(EbKEY^!IHl!DX78aa6>ce2{t>MuJiniy#x(k z$<62kvsoAIpvnECi-_aycm+<@X@+l*9B@5Hc#2EhW$-WTY%|5FO>LSL;99~1SZcQsIyEbD#^A5*I6<7n^u**m-Eq59bIAj7 zZIcEdGOy#B>JEc%L9tz#e)h-0IG8Z;6B|kM{t6lHxvqG(B7;eGlh|;%e4}YFIAvSu zKwiWl;<}OPm*)XMr~ayLyzSXlza99eH%eZ&J4gp@71vA>m9`#)oqv}!k8F4ovDd@Q|BHZg9M;qIlSa-fM)== zoW_KGR6ci<)zlLSa(py>!Sg1 zjzj5~&IL%gm%K^;9RYS_8LN#x#Xo2}vp0d8ceCpLb2@voD9L52)*YFEjNw zxR85OuWmEmmAMb>6#ar~CJ|cn<}g*I9+F*6vl@~s3#?}H%r7!f&7o!Oxri< zZM5pyr?~Wo;s8b4ES?p&3qC;JtAP+sL!epAvuUV4WISNo9&a6IA`+Nm>Pa7qQ2-=jgB)Bp8;Ah_nlv9`QMT=`1KOCdU(5nf)l z6Ww*#LGg^;FYwfukO_Dh(@Mf{Hl ztqpNkkD+Wf^F%Fi#w7*T7a?ueiodfGXblVLRd|W>&9=;fyvWJF=dxbuaAE-yN$sUQ zQM#7u-A46(jP^0bHka+$5c-r(&Z$<}CV$6*g?sh4va=R^+q@=e!}ng@z*;Ajz#3O? zeO$8lypC^R-`1*UI*fnQ9cQ|BxKk_AH?BF)gnH)82wqFL z-yvPoGcr5$l@)((--DCgE9p`4o=TkCVU!yUgh-nAx4VNY_+-QG39Jy%X??rGs&5y?bPdh|AGcHiY@(j^X&L@Rfq!(*!(TUUyQqwLo1j@ z%~KBOeS+g_@aDBgYg((mG4xBhICiu9-wdUgJ^GfIk85u zVHrZx(RF=V+pHUM9QL7T*qOI2`glDSyp#20x?aNz-MG8$p7R?ARkmeL6hX(_r(;BV z9?2Gku` z^t~+Gz>J;}J&GLo+S`5z7_z?!4->o~&et8&5|sDJvxK{@oQAfZ+} zb^OFY!#;Nfbf`hKca383W|EpY)S7!ap#$|TOj6Gz{3TFOmFUmr zB=Idsj~wCzOL!C!Vf@_SW49kU*iJ7S7d#0M=? zw^fk5FOx(hpN7x>Vbs5f&#L=j4oVl)Q&#+mADWPj_`a22hsPb-k6h8+ma&E+#*oDc z&FbD3m6Ab6#}0o>d$LDB?nI`F%Y0%a`u3s1O7pBwsFPh4;v?Lu#eF6c2t0YT8T0s1 zi3`k_pxmE>&P(>H{{KlthG&ad5S*-3DRZ82iVIe+wCNu_728XL_rJ7mOtNT*(uCr zUrTLap7v3GdNvaz$ziPBiyKk;zUx0qWg;A1oSP-arE@>UxnW3I8GqmUK|Dw)2F?jW zKlbi?eGKWw-M)j(=N+u-^nrcAg*FxIdBnw}No0xoBeDH+ zf+^!gGi#_6)wA4_vjpE_<{3Y9cr4B*|f$Et$MWn1z)5d*UjRp`{)^S$SP5UoAdpIjOKGdc=WtG#mjx0^}}BIp+e`;6N680o|t{mQvK=>%M7*$d}b=l+R1Ob#zu zw2*&Bjsl0h(y{#|vQ8?OgmwxeD=s0_ioBQHY655XVYG|veAEuuPavRkG=bR zPV8ynEa|wXtq3oD_yankAmG0p*+spC{EK8t9=UpV%_1IH74+Oc~9K2z&e64L$=6mM1o)DW1}AO z6MZc9@rv{1D9`U67cDs;e}ZC!`6@#Ix};h?IA#(YvF^jX%pgW?K!#{grj=OAi- zh>-@Ayo{2%Vryu)7^BBFkAaG1&*vxOR;_0zA%}nP`%0vlHkY^ry0?g)%kAsL+2epk zbn$5a<&7L*jEa3UX>csYkaBWFhsrBb`_Gm-ynqos*C{R)k~1>8V+0(_MnUd-_YnN_dFQc=vZ*96rff71#VyNgHvxJgZAp_KbE~rt# zdN)(dHGyB{cUgp!E5$C;V&}5Fz(VL?e%z`Y`TjOr07hVN)LG# z5MIU*Gu&+0X@zv_-#p2E|L&01+Y_FJ4$7ftd7${&0d8}OUAezaDVpm0>CQFPV#H@D z@S)h!*0SeDG0oceo*#-Rx7Z&VY?n(sYNn)BG0-Xh62g732Z7H)h&Cp-sz5@3Gzs6i z6|g*DBI%T@3au3F9)nMBj__5;x5M%tveCf6S(*+WRo0rI-^P6@k%jbtn9X#{7^@|r zdYcuWP`vSkNx1VrqF&xWu9U>jGOw_-+e_HDK~Qa;=A5zB}?cX^iZ^$uYW6Coe#skK}ngN!O>V#rh)uP}t`( z*g#R2UT%X{>R#ZLn~MrX+t!FcH?GxxIj?0ZdJz_5a}e(Xbo_dtw@rB00cg%72Ie5e zUf%3jri-X$$UbPdkyW=-rWpI1PLxk!NF3x-gvn-D$TCsk8#>6w!IScVU2n^sKfe7; z6}0{)PU;h})*OT9EGvk^6kqRaus%_%EQY@IR!VYk7n6cuh#OcY4q?L`i+!x3ZEs%} zI`Njq-QI^E7l}M!#zI=j?ABLA0ja*}BYyZ$5PguE73nCsv+X>4V%uw$2@%~?MsYrT?gQOqi6yV7Z ze_xVe!LBxpD-5My%==uSzTHNB$#nqpGzIe9i%nyBlU8^^Bd+yiX0=n2vo)Kb!lkyH ze_xP#6yVmoLaVmh#d>U43IqNSKf$VEZ&oIzY+t^&f9W3N9*KYHW%<71@AlAXv<$N& z1Gl8u0aW`@9&aI8wl^7QW6gChWqEXXXInStFYXu>b>CH`a)!T`M>Pg@2X%?8t8Sc)U!!4h|#cL(9 zIK-HQmAxnmNvx&V8$tW+*q9Comu#=%Zp6+S{VLlccYc@x>&{sSq+hX4l6}-^`{q%i zp>g4$vLaO0E)FT9W}#-^WdAYdf08>sx6l<7G5jnTwLwZ(r&Ioz7U*LRbhQ44#DBp7 zURLM-leY~b!Fcs+(6;vfFlOjnmcN|{^v)_U)virv<*w<3JGkOA&;Jm>#8WCxVW7fb zdFvwZ-CD;Sy2u*OWzoVRuvCT@^^D`A>!>S|!7WibGKqbkzw0UGxZC_fl4+1nAUdj* zBJF@R>S^QsJ6l=pf3}k*S#+*~h$^o`yTxyD{CyEf`p?&b-x5t**?v4@ zX+qm$9U6j83aeT&MPh`;E3Pq;3jjeMj1fr80am|OquI#WByokYn zWO(<`;koO4Y*4Mi{v?J>X4gfaWHA)WGdg6n2&DQ!qd*+&SE1!6>6XBGoBLYoL$@2UPWL%_QtVD4Dz{#?#=aFvG4y{ z*GLL-X3`pT6xQlIqM6G`? zufJi%zj}Y6WIFj{9FRs!82&P@L0jTX81Bh@4K~xD zXmq7pNAi$@E25l6ltJ13(M@&7X#Uxbf;q!MfIYem9ewsJ0hxTf#x7#|S@`moAn|LL zIPm<6614!caPDF}PX6UClNp>;Pi`U^FYkSl69FCkcWPJGKwCwBcmxIJzke*7EI7 z_43#K-SDtx(!lhEA!zB#S?RQL8gq-!uI;(stfDP?+{I>nY=$b?GEp?}W&Ai~n7P&F z#wjcZy~w5VQ3&tzD=y)o2%92uF3NBYs#7z7M)TB^yUglK&U9H9zp)+p8_ADCV^~9_ zP$)b>%)1uD%5@tny#Bj#jvHUbbaL_q4|KyH&TdPpG3)Fz=ZE528bUC_5qOqf=e^*E zYT2aF;psql(gH;`jew&Q{AswFoX&97YEu-x=7DN{HZ;In$QX*0SDz$X$|H|b5fz3O zVjkZFPg;A7_B$FRy_p@38vyrR^?ri8f(G-)+^*8~oJ*{a;N#wVl|y?l+FmMY4L6bp zg^(BJh_FeR!O^={vWqTy=WW0%dc#}lZNu=(4VC1MyjA0(tFAkWS>z_&V|VsUYV%S= zv7jA@!9Z%FPD;;&P2o#Hh9ttSw+ zp5vq(WPDnfk4iq^5YlnBRIDs{0CkPY;O|);6xv|#72f5+p=!pmyWz^exCIOwz*60_IF`?9m$sPMopyz>)4)8 z123N}EDRO1}h?KZt4xt^A1N-5?M~E?cZ%R=y}Uf~ zDa}1xA;V0UL9?-SatkHtv!`{&-q~UWJN#;w*(7vdJ991*zH=s0|KUcg=Nll*Rp& zWJ$X?Y2n?TxWIT2K`djseiZ9~jj;1E0M~e{c~$Dly*}qLG50zV2k+Ap!#X%c*g580kVfJ6Zu&*42X6Qc zD-x^n!qxmd@lQKfT#{C2UiQUP^}F=#JdjYX#VIEs?eQPM~&~4Qw>$`qOw^aG%9zhWi z%rhe2rTL~i%@|$H_PAy7K-grh^H^Uh2KD!V@c>iv%A^`ptgc75G_w9lO65pFEPMo5 zSkd*W0b=1dq*C(~BBM?)w`B7iF^} z4rYE1iLl-9_YfaP%{{`{H*DP(kMuq3KA86r7xKm4Y_Zc1244`MW*_J~mv|TI*@x9j zzWc;~l2{+*m4p@HJv~76@_>D z_;OuMtvaU`4(aOX2r#1)Y8i2Z`utF#Dn6dyKvPX|eTK>o2Qn?)#<6h;7w>Hr%dnOA zEqrCalyIC;-IewcZkZlm-dL-%#p&zISaAvOe$n9xiG~E3rVUR!Snxy4>0tYj8d+H( zkITmW+~A#5PQ++JY4hHC+1X3B0J>o zk10_TK)kWXJ@EOOqIXk}{Wpeg2^BI;XWVKPQ@&4kSz#p&_HL}&tiW&Cx0L6q;k$Q- zr;F9(BSWMa*+YS6=$^Lf zMcy;qc(=emW$asoXqhaFd@Cqum+*&(GTxH{y>gRv=y*15bB%X1&@P-NN*L>K7kHJk z;-_ZW!5a$h$vLrBW-aAv5ZS{z+EW^!RR~;>+|XR`oV^u1La>55qgS)qCRqZX-E0Tu z`Xi~4YK%*rtZzSP#&o-RKmmP(eL4SJ(XP29?t6O~bpJ8EtnSPVGTO()Gy2`?_e-kb zu^-|5J{Kvj7>7UO;6*3>3zbwy5?9mu951m!U!PR^uW4)_RSR%bDI0@G7*P|C`RaFY zi9UTJq$W=b6>wZ5rMIe6#w)9Et}R$HP`1A_PXM1X-6X_eHL;mx$E{%TMX$HPJZ9JJ z5a!X%a_?J-i}Pd4Y+MIy-X!$X{f~@Lu06MaI-W(_nejvZG$K2Ut5eEn1cjxIU}ChG zIVh(x^V2E^GjxLla-+b>!JO5?LJodEKBjU3&wDOnFV$p9T`8w_)1O89lRPk-W&IsW z&Bp%xS}%Hta#yFipt+-s*4zrduSX>C;M_prWqN2I(L8MrPG+U=O~LxzKbm_E=!_0i zu(ra+&xp2?GX}PPGxZt%?YZ)hDKA|2S0<2dZ;=jv5z6i&$mm;JLkSkVP}OCAXk~)P z4sF_W!t*^Dy4JkV)Z)E#LxB^>JDP%b)Zl6KLZXBI8{f%X&E&7Qs72#ZR&LPi6nle8 z7qgwC@6f2e%C2+uI~Kf&hxBmDs(HIMj6$?%SDD!YD07f<%eQ0uQ@@5ju&}Lt9|)I6 z_a4JK7)Au-Hv3--KFz|Be*tG{#^|J2y_npbl#hOGAY-4VPuvQZ-J17qntKMx`Po`~ zS@T1+bN=tl{Bn!T{C0x|->$nqlsx_)+h1u?+Dec~8v+-~Kyl}YxytZlf|;27I`tsj zWyAIlC>?F(n#9pL`6aQe+e=U<71Y|V2a9hG6Z^DUIhH`scL^~ur2dnfOc z0*{`wXYn{OF_VSDox*dC{zKeTe1n%5GV z66TalX&d>&r0TMfye$_VDXvj&{QR%iH+O-wL>-NWMhvW!_JC~5BBHf$QaWrr(;{(o zJqk{)(FnAa@=Z%2ChD)I=}k`ZLJIj17QC)f@@gI_trjjf%#Ww9R*>7mVw%{D7YK3X z;d(`**!+gUI}kg3KmEu;*v@4%u1KP~c-g_Bh`Faoo4QGBWEg)laKy>jr&M(2kCmD) zbe2yP6e$w&7Ku;T_ih>{Bn$>Gjck4e$-`i#)-RZ@_WTfVe!^Q(O2wweew~N0W@T$#e%{tk^L_1O zOw}3*F1G?pe#Dy)4uw!RdyYl#n*!Nu1M@^$knLgLFzrY62j|^w%a_x3z|wgih(o{T z@5B3XuTAgbngHf?66hAcA)^=mh9(t(3L~PiEqSiy=vU>?y|*%pFCW{!!EVeIRC zxGOyYCj4*YFufI4%y+(CNjpowW-u{M?>~lNlhsWNd!MSld)2I`PIdL9cmBj|*T(s< zu(08_>3mm9Eq_)3>(S$3-@+HpLzY6XPz&2q z33dq{F`TD4UYToCrck?N=day9b%iJRPJ2{Xx##nwn;fe>7vB!-xfB>e)Bf)4t|j{6 zvwGeDPI8l|P}InL*bFw{9hvd1RF7VpIE9aIAy(&3hInU9 zYS9a?l2)~`b@y7 zkh!u_fU~y`R}52pz1~YC$k5-9sDBAo|DqI6hx<1K55nK7#%l!mscm3+LZhF}FR7jh z3mb}TpdstE8MdjhmHm}I88mTfPERN-v+#l%3#uz-$}{W-vB>>=-d5T>f#=7EDkmA% zJ@89*^s+MS!h54&1~yxPOWcIUYkZZ>%uCRZLh>!(VV1)so|$k*5h!*d^tid8{@B=J zA*5=GCWU3ysJEvzZl>yW(((u9Mrc{d$2Wy$Guf%0A@+d>;pF+cdQUTkpO$o2QPBh~ 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 literal 0 HcmV?d00001 diff --git a/caffeine/Assets.xcassets/AppIcon.appiconset/29@2x.png b/caffeine/Assets.xcassets/AppIcon.appiconset/29@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..335d77b43607813ffc38ba7922db4cefcb6d5270 GIT binary patch literal 1104 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 literal 0 HcmV?d00001 diff --git a/caffeine/Assets.xcassets/AppIcon.appiconset/40@3x.png b/caffeine/Assets.xcassets/AppIcon.appiconset/40@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..faac9b6a6f19924da8825efae0ac296ac2803e6e GIT binary patch literal 1979 zcmbW2`#;l<9>+gxVPc{XayjmOzZ74#;kaLChZ%C&kfvOlOOpF-Qmi;fE-^%CIWCRl z8pafjue&jGjnpF7SfbR9@A(hT`QiO~J|3^<`|)`H_`dJxfP|isIRyX!6lH7We9V}? z2Eu=w2EK@iV}K%@krqJRi0m2w2t=Z+%w1wYnl72#ip zBC2WS+^xRZPyONuPmYR_6Ua{R|&ftDv}YM3DR+=r2RI61*WH}g(@YOZ^B z5H9>Z7do%`#L&~B)_uX=mLI~lPw)}E#yX3$lo~du7V}TUOcg~4cZD@H{yB@|CdnieNqUPsMVJBVbn(!T6 zFRHGFvWvSy-sB-8z@8%cy?Zh^aOC^tQZcb@!ZIaGR^?FBCG%{S4Sf#6&AOFn7m@J-@mWnwwtd>dso20sFCM zgSFb}@xv`+7jzvqQAJ3aW~}JHQ3-KA)-$Cc!W^(5^3ex zN*WW)91@R`9{p%BoG@q#q5lM1x?Ew3vhrG3cI(cxd=n=oXG|*Gju4I2ofcFqyX5*( zQ8i0^%4-h4kscj%Bz}WB0w3RJKt>qBe-oUL9&e1QUmKHSv?dQU91w`W%wb{skozXLey1P+3f@HMWFe#AuaCA=5Cby#SEu*Oe5&ELLh9*PN`&Xh*GRq)h z^^y7oE%k-`rPJ3Cqne`UZZf&+?X*Pj?OzrpAvGh?toOo`@-V_(KH1o1{PnH48vU=G zO!ttz=Y7)I9wqPAO4E(c{h2*f7(C&&*Q)j}YMUmv|sFx@1)FG7#_xR@HsL0-* z;|ZoPf;ALNKWYmU<-Sijt48ppR)K`bP)n2UCZdu;GENzWzrDw%o9%I#2Ht7nW5jGj zEy-SB$6AC1fnqKApAzo!XD%Lvr_&g`+4##F;-1hU1@$8I*w< z!%2F%o@Uw2IGJUT@;B$7=!0)zD`5UELHSs5ls&()Uh1lGU|Qyr9y-nC!<+On;kU*k z6vE=*1+_Dl50~Wfe<%;bC>TA?n8OF3AoKeV3LI+Kn)jK-|me)Q%BO7<| z&fZs|Lg`_lNxe}wWpOv&GKu>4;ILeH1AP)e61g>PrGLV*=9i)U~Vtn@$x{)o(iS zhm8KSAjNDX7!{FHRaS1fOw$!;2ILEZ;tPO2ycg^S@IBVo_H zKHv{-=}4{OR0W^fy7^~-GV|c1Pah@6`m3erwhUvHi`iz%rWqjF;I*`ve!_0K{*jM` zP?Hq>h|KBhR^xS$RlONa?Uhcw*Qxn>*MP>QZZ{liY zfC~~=Xoc~L168NJD9a{?8|PAQA^Zh+l3FJpRT2%G$xI I&H{huKa{h#1ONa4 literal 0 HcmV?d00001 diff --git a/caffeine/Assets.xcassets/AppIcon.appiconset/60@2x.png b/caffeine/Assets.xcassets/AppIcon.appiconset/60@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..faac9b6a6f19924da8825efae0ac296ac2803e6e GIT binary patch literal 1979 zcmbW2`#;l<9>+gxVPc{XayjmOzZ74#;kaLChZ%C&kfvOlOOpF-Qmi;fE-^%CIWCRl z8pafjue&jGjnpF7SfbR9@A(hT`QiO~J|3^<`|)`H_`dJxfP|isIRyX!6lH7We9V}? z2Eu=w2EK@iV}K%@krqJRi0m2w2t=Z+%w1wYnl72#ip zBC2WS+^xRZPyONuPmYR_6Ua{R|&ftDv}YM3DR+=r2RI61*WH}g(@YOZ^B z5H9>Z7do%`#L&~B)_uX=mLI~lPw)}E#yX3$lo~du7V}TUOcg~4cZD@H{yB@|CdnieNqUPsMVJBVbn(!T6 zFRHGFvWvSy-sB-8z@8%cy?Zh^aOC^tQZcb@!ZIaGR^?FBCG%{S4Sf#6&AOFn7m@J-@mWnwwtd>dso20sFCM zgSFb}@xv`+7jzvqQAJ3aW~}JHQ3-KA)-$Cc!W^(5^3ex zN*WW)91@R`9{p%BoG@q#q5lM1x?Ew3vhrG3cI(cxd=n=oXG|*Gju4I2ofcFqyX5*( zQ8i0^%4-h4kscj%Bz}WB0w3RJKt>qBe-oUL9&e1QUmKHSv?dQU91w`W%wb{skozXLey1P+3f@HMWFe#AuaCA=5Cby#SEu*Oe5&ELLh9*PN`&Xh*GRq)h z^^y7oE%k-`rPJ3Cqne`UZZf&+?X*Pj?OzrpAvGh?toOo`@-V_(KH1o1{PnH48vU=G zO!ttz=Y7)I9wqPAO4E(c{h2*f7(C&&*Q)j}YMUmv|sFx@1)FG7#_xR@HsL0-* z;|ZoPf;ALNKWYmU<-Sijt48ppR)K`bP)n2UCZdu;GENzWzrDw%o9%I#2Ht7nW5jGj zEy-SB$6AC1fnqKApAzo!XD%Lvr_&g`+4##F;-1hU1@$8I*w< z!%2F%o@Uw2IGJUT@;B$7=!0)zD`5UELHSs5ls&()Uh1lGU|Qyr9y-nC!<+On;kU*k z6vE=*1+_Dl50~Wfe<%;bC>TA?n8OF3AoKeV3LI+Kn)jK-|me)Q%BO7<| z&fZs|Lg`_lNxe}wWpOv&GKu>4;ILeH1AP)e61g>PrGLV*=9i)U~Vtn@$x{)o(iS zhm8KSAjNDX7!{FHRaS1fOw$!;2ILEZ;tPO2ycg^S@IBVo_H zKHv{-=}4{OR0W^fy7^~-GV|c1Pah@6`m3erwhUvHi`iz%rWqjF;I*`ve!_0K{*jM` zP?Hq>h|KBhR^xS$RlONa?Uhcw*Qxn>*MP>QZZ{liY zfC~~=Xoc~L168NJD9a{?8|PAQA^Zh+l3FJpRT2%G$xI I&H{huKa{h#1ONa4 literal 0 HcmV?d00001 diff --git a/caffeine/Assets.xcassets/AppIcon.appiconset/60@3x.png b/caffeine/Assets.xcassets/AppIcon.appiconset/60@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..5e3ff037255648a34e92320ea88e0a014b003488 GIT binary patch literal 2872 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 Ae*gdg literal 0 HcmV?d00001 diff --git a/caffeine/Assets.xcassets/Input/Cups/cupMiddle.imageset/Contents.json b/caffeine/Assets.xcassets/Input/Cups/cupMiddle.imageset/Contents.json new file mode 100644 index 0000000..0fb6df6 --- /dev/null +++ b/caffeine/Assets.xcassets/Input/Cups/cupMiddle.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "cupMiddle.pdf", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/caffeine/Assets.xcassets/Input/Cups/cupMiddle.imageset/cupMiddle.pdf b/caffeine/Assets.xcassets/Input/Cups/cupMiddle.imageset/cupMiddle.pdf new file mode 100644 index 0000000000000000000000000000000000000000..c04a2b7e6b8172bd94dab5a5014e7f4a771e4a3d GIT binary patch literal 4116 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 B`|JP! literal 0 HcmV?d00001 diff --git a/caffeine/Assets.xcassets/Input/Cups/cupSmall.imageset/Contents.json b/caffeine/Assets.xcassets/Input/Cups/cupSmall.imageset/Contents.json new file mode 100644 index 0000000..0ba00b3 --- /dev/null +++ b/caffeine/Assets.xcassets/Input/Cups/cupSmall.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "cupSmall.pdf", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/caffeine/Assets.xcassets/Input/Cups/cupSmall.imageset/cupSmall.pdf b/caffeine/Assets.xcassets/Input/Cups/cupSmall.imageset/cupSmall.pdf new file mode 100644 index 0000000000000000000000000000000000000000..e3376290bea18e5b881070b0878f8b3c4a4e47ea GIT binary patch literal 4115 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 literal 0 HcmV?d00001 diff --git a/caffeine/Assets.xcassets/Input/Milk/milkBottleLactoseFree.imageset/Contents.json b/caffeine/Assets.xcassets/Input/Milk/milkBottleLactoseFree.imageset/Contents.json new file mode 100644 index 0000000..d2c0c0e --- /dev/null +++ b/caffeine/Assets.xcassets/Input/Milk/milkBottleLactoseFree.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "milkBottleLactoseFree.pdf", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/caffeine/Assets.xcassets/Input/Milk/milkBottleLactoseFree.imageset/milkBottleLactoseFree.pdf b/caffeine/Assets.xcassets/Input/Milk/milkBottleLactoseFree.imageset/milkBottleLactoseFree.pdf new file mode 100644 index 0000000000000000000000000000000000000000..2f122487788314e694093250d8ac21cabcb1b466 GIT binary patch literal 16387 zcmbt*1yG&KvM%oK?jCI6?(XjH?(Xgc*FXsFWMRSG-7UBUf?IHTWXnD0o_*`xs`nNY z>!1F6rh8_(x@JDUrc@G>U;r?(!cq3`U+o{4UVoYHAB1BgVJ2}jv4P{`BVm#=cd&G` zB4K|QsgN*9SlhXoyS#tf8M~Q_nVUMAnUe?zz`44)m>b)}d4Z;>$}9FUBXk^Swv&@I zx(Z~MXi_=om1ulNj>?3xNg70Y_WwLrO-DkNuU1RAI+e$79Eo1Bbp(~xMA(kb2H4(( z^lk6kMpuz+H>u~>weywH$1au^=C-uPA89ms$d>D(%t4X!s_0dM3D*3)g;v#<_VGdm z+W!(sLwh!?iUP;xVRU*xYF@Lfu+d0NGJIMK5e*D8+HxKnQiYvi%rXXjr9j;i>{{hh z6-kUF8XIW1Dun?hvI-SiIT?08Mx{~?%Ra6-{hD4x8%7qBTfZ}Hn`M3DIz!vG>Ut*Z zx0VZp`aq+;H=+R>gop94UpcJH`mrNgC6=%vN945RG~7EEo3Nigp%0$J8jj7t+NxB^ zM6woe>YO&&UpP5$K#n0SEIxcM-qK0CuNKdCf(g-T`ev~!6L{)`T1zGd8N zF^q-P2kNzv z%t@G(j4l88>tgQUM#B2%#;cgSI=Z`e5_Pn5bWwFO zHZ>>t9eJXzEF@fi8FK}YaQ^WqAn+c1@21~1;F#1*0VLdii~nT{@Y{pGjr|qB0KlIk zDZEdJN%(gVJG@6Q36q$)hqbA>iloT@9^2vSx>5M*IIk((BXDh#bKe&jibOlyXxn7J zVXhZ9Wb39h*y7c#EMN)Or=*yTpHNK7&BFWBh3v#uc1jDkcQC+&%=+{!LO-dLD`|Kh zlhFt?cnQM*jroo>)F^Lu+@}cIXOII*aky(@a%DL51Q(`auetF@eh^-qP8DWEInWWrUE0<~t@pXAY0vdrO~G%2 zTH^#iPxMu*aeSnCdp2t>8V((!q*T~=bKiA;25FDM^1CF;h!ZJ-B!G7rR1;!xcbDE| zE##oL4_lt9QBqxDJnv_~Mb>o}c6Yh()80f;zUVg9=MrcQPqUISn$&VN<@jtzhM&j? zKoU7;IedDUH29`Bi&VnPBufgc&yr*;-g`zd z_*28y2b5Ag1{3v>FY+ohlF~6dI@IXtXx2rc+dvm)0#E&ku==S2I-%~%T|7r=>OF5Nj(uO5 zrHjkMdRDtl+!q+3*>@f;i15bP!QfBlPnnw`kinQjrk}_tV<@{RLo939{Ma^;=zB}S zg6&Fqg*CTO4QyJ<)Z(Ud%pgwRy+V3W_Fhz{y^7+aEZx%w+Idb*d~z&qa=F>3DR6&s zJu>gm zF%!ilqOB3;z$!o@!>;+Khqf7g>d8KwK)l|jd!*av5G3uS#;9CS%+_f!`QY2TO`QfK z;IAi*f3(-EGVMM9(2f~laNzKEPVV}qaC@<$p|A<_R^ z2k`Hi`tP*%S9<>cNNc(2o@%NqSdmj5oE_6>WF(X~cs{Tsv%FH65X#ZgK}ui|VN@Ps zkP;ZEv>Ik=-Jp_@WTxU6@S!0lOR!fcN`pPhV&ePjakjAM)$G?B*)K!dn=1!RODmS= z{!6VOO3xt>y>42dL2UV27-z>ldT8il{dZtED4@^ED-<}tbEvl zDze@FuXeYkKR&dLWM)w9<>P5j;G}uE4?Qd5po|AxFL4q`F z7&od>&CteKU7yfOoa`LwrUIK3)V_xG=mEZT-Xl8 z;h=`b4al{{uyQv9@ek)#YLUB?qT)5cC1_Kh{M7zzuh{TU950bxmOLc|CX} zhS!U6*p?F}Q~hy^kYMIQSwN3lxEW^G1BR9e?e+zZEtruRjNS;5Ac)loe1ileEJz9k zJRO`-3d~vvqE1*~83axkung)EYU2blAM7&?p%B911f>U|*^TG~j}Rm&1Q*dG%M7{^ zYz-4~fr42eT#<-Xgq$U^h=Q*J<1H$z#DxJqAR3*Bk}UKvO;v_N7g~`os>FXo?uOS2 zqaXVC1$vr<4eABdKMXY!Y|a>Q8RT2g3XqooMzVKoOUw&12O7J3bz7zxO8}{<7keB3 z0)#%?ur~!pXcz{3MnVe)|58jOQHuf;mDDzgtO%@JJUbDo2)`v>D#>{d94a#3I1>kJ z5O+6HJ8s)V!+6m|hIt{=G*d$k`v->w3TyB~NU_O6ZHX3jm7oVK2kNJIhJFpB1S4Hw zMlJZV@d+;h(oi?<4uMlZGmajM1A7fb6Y^4AThMVI;x^T#S3BJX#(4;GkL!hrA899C zAVDC}W&-hG7j+`64uow8GHE&qg&l<&3LeY>%u5(*FPn03nW7t61d4aRo(XO3$7SJm zX#y&R6b$JI3Tzb$+N_3PHEA0%eJXyc4$_nn9y3W79Bm;3#Ttq{5<^PlWI?4=8Y&D$ z83J*U6$NgY79npTZ_#2E#4?9@t%}UnTph&@F@G6qk|fdYO&xSygb0<5J?<;u5aeezZ*OPOWl$wKjNbr%ijHbD;A}BTKVL15Hb) zkW+VDz*xwwu&+>@XSSiTF}7K;d0JqsjGro<^87rNYsmJt_Z)cyY>oD5ezf`3cf@~` zf|rfgiHD1)j+enU$c~%skUf&UpMAhK)L^9p-w2_zuXE67z?_zKHm+ttSs%-tUtM!r z$}l5Pv|hM5cq%cR9*_*MBlUqCspInEWo|&&Gw@rsNe#l{0jOI)%K0T&CZgV=e`Db*X^Sxzfqf@gwr8 z%kvv*My*o~QwX*{tf<&3+1rK+fNR>?RT7I|xcm5q{R+K5J$!)YkJXCJ#ahQQq(7xs zWjLlM)~3~l)Ut0l0zUSA@6Wc?H}xNiu-P@OpDbDb(O6y1u<6lt>d%|44_wD;Q)rvI zMY<(>qIv>A^GA9`b|Bp?yLr&Gh50X_9v^NuPhQ6DLR0%v*Um|oZsuxF(oP~y7Q!Q7 zUtrHO;JC~EhsV z=}8fS3!)145UvP90zv~?0GS=}qZ%M*gZL|ja?zfCG(cy?GaHXchB%Tr=RazK1RQeNCwJVRVILyKO! zeorD!Cyu0qABz|t)0e`-rTlJoT{d#}WCw2djFD9@z5e98OXGg|*i=oTVUM;m9T7e; z;U>ykG|wOZ|KE=Ol=Xu)44rv5bEGXjADLX-w%| zFh$|UE%!RZtKhxz)Wp<6TGsNJ@(Js(hWmy&5lZ72;0JwHe(DaUKDI(;(biGxg)?>Z z0->2CIT}}Oi?+; zWL1CuV^E|;M0vY|VNw^#Zom%H?sVOvzS?FrgUn#&m&w>p%#I@ETJrIxw!h}X`uJ_w zX-DyG@ssD42aM<1`p?#Dtt=C5gO%x;E&b~K@vDNXrZ&x!P7PySXCq|m1ha$&ma@7I znXfjI3#CUzN5Oar**`jte49>lzYnc0b#2-Q&Vj~*4?qhLVGy(j4&N!+Rtwt?7_V(t z^-UcY9JO{?1{wy6ol0FMO-Y7J77z6%xG(U|FL9P}rgHSgClA){IuAL%Z2c1TMX&s+ z#9G*L55YyseYrDqPkjCvfp5h-#=qhx^-JFEw`rXio&3eM#prKE9M-;azMDUT=5h%q z2^j=Gz4_h5-DYLik6Ox3B~4=HeB#dY47d^*48M$x#*XCCbQ5T8*qhC*0oH7c1!sIU zxNLDLU+s8$R?n!ktl`$@_0RS1IE{FTUnFY#oNjm$VEwc4+`i+dQ~gW&ZuQ4bNdJRJ z{U@f4+gAVmk8ip7;IUATXN;Y`Zw71pKm9jeW}wTF4Ft!1xL&MYOiy+TsNodpK351< zzbxD@S(JC&oP1d_nyQboOo(U}WqM0{_^Q|kIaNOOL83w8NU~aTD()d}-KX|u;9@K; zV{SLRi}v-~UD`}#UV!IQho#9#|Ap<$ah9OWMp-BKCI5m&lAOa#k9P5K~F!}=PNHNdy5~NcVX90|HGN~_c8SM`IUtO!1DKb_4kGS zA7|R%XV`x`)BfG>_kI6g;DhV`3@7|X2;ASV{s0mtS!*-bcl_Y5(SAcvf8h*(f5)!= z98uKR&DhS-@=sjD^)Eo5r z%@3*)>e6D?u1@l%`d^;^ITHnA`*(=s|2ADaW6SpyW%*NGdOW91?NuyC-y-(uJ} z-?1I(_dT#S6?U++Gk>22ld!AlZ*Ym5{k`jNtG^ozENt(~ENbi|Wo~V07ld!Y?C6^-M;(i~>!}5=HB4OuvZ^;{b{n-MrbNuDjJ7#Il3J3TT zxB9m=_;*O^@9Wf`Ak%;Bz3BV&{ukUc+{aT7!*Yqk{D5dVxR^e)wZ1Jhr~@npj7|lz zC<=}SW?32agNLc+i3yvqX>_ziVeMU%K1NloEn0l`vb>xeZ@sUD_XaCo-ns9_LBbuU zpl6I+%as49d(E+j$7~B1H!trew3HN;6xZxuQsXioiFrKcF9K3@iV*R*-1MSvyK*r{ zqycR-SenH(HBFI~>gPqDHkX^6W(wXs_j;JF)b5tBvVMVDGM>N>2lLJUTaBt;lLbUr11nM1g+RR@FE0q4M%#q+GbbH*;KDTrFy#E|4 ztDoVNQOk&}|GIy)GuqPH;?r8vtl*S;Eg}B_Q&FPh9UdnRc%kjyKiT6Yj>^0Ze1re%}YnQzYu?6Lu&TuGsA$2 zluWB0GGM@b2wxxyAmZnj;ivMYzi_)^^B(k~^6~gJe!;inJ&KM16*{9dWCW07lVc}f z%>n2E^jOz!ZFUycD$_KpG&#RE8t``9`uHDDwDbB7`5yQp-x_S`pZPBgjZsffFIg5% z@#R4Z5I@>otsJTDyY?K!Ou6Ts`xD(iZ;w4ZK2kkWJt5ubZ}~3YMW4fO8v1SChtzfg zR=B=v8S~lj8T;A!Z66#R{9Nk(T5IUqr4djbpdC>7LUk{H`)Rvr-Z6YLBf$5$;>F>f z|JRfLe6&M>@C`bC%xOOkKzSVNDOP;P%ekgm?OAJ$;tVq(c43F|Qung#T*8EhPv+Yp|Y(s|565bv1Yf|8$m>r`CFrfNgPbPa4Y1aO$$MaanLC^)Bp}5 zXfx7*DIAo^REq|U8PlR*1!xBZV!&a@h6^uI*XQx=h>>L&ePA1GeLn4@aJ0J8>K5Hv zDON=|5blo7K9yMu(Kk(`7)7&BfL(5IgJ&5b*BM5jXQ=Fya}En!bPK=-YTu=eCFb;U ztNBIn)^hvqSNJr_{>bAG?nmEPP9lD{I~0zv)?^U*6U!H4D%GXjnO(l`<~m$oroL8Y za_z(P*?&{ralwo4OHob9B!N1HMAiHnv5f=DN$CYUFpVk@Np=GUnqZIuuw#n+X(*}L z1qddF5frAk7r{p`Fb_vXNFVPJMv1qitm;9F8>GxcHaJ8)ZXHcj?iQAK^^`7S&5v@| zN!)HNdtlG65pdXBZ(C zg}~P3%kOz|T@}SiLv!ynnGtr{`M7n#wRb;7##wx*p3V^d!FPf{l|#9$@|exD96BCR z+(?LH5C-6av$4hpFWf3{k0N@SBWCL!X?PF?Km6*yV8Ayd%n3z19jPn9ds3LYW56|( z^fL7P3ZfyHk!E4BPJ=|v@?5bP`bm1=@dk>nyxywm&~MLp}-cIj`$> z@7Wz~od9Zsv-`N99YNI?nB^PSx3F}L<5iS@=WfTaeUSN){8G{np&?TK%G%d9$?o){ zyc63;VNbibTATzv|06CMNKPvlXSP@6Ju^WrAHd?W`f0vT9$x#Z8AF(CnO$Y zPQQ;#Ky-^OZd^_PsgR?U5rAzTzoJG$yTLf08e(?MO_C`F)CX7I7{x78j#&sLu69S9 z9<$Kr4F(HH;CuhlL5_+Ow7B+-&z&N>&O#mvsVFFwsVh;gB*q{k5J^|5&gI6Z z=}BwH=$RBgqR|@;Rg@koN#rXnq_JuwZ$c<>Lu4}f&{&3Jg9uyKR%p+)Z1Lg?Qb%H% zpb-i8o>1l#{F|lJ%J)i1F)MBmk=^{y?mt-^90q=P;}>-?3P%25k?UuR+d4)*PO}nM zm4z7qPsUTJ)`X{tx_d$Ie@gY6=o7&W2wos40$3rh5I}1AjxQ?wd>c-Ix4GdOxW$hI z$5klV1zUCWq<5;j<$*TEm8;9$9mSP%PCQPVC1n1z_LXQafN~dP(ap<>3XeigjML>t z&bzVtgai4G85U~C0YP#Tf^AUClJ(*!`iE{NO;TEc(qPU{mK#eZO@S&XWw7Hhk3-5K zrI75=?NVZ;kR4zotgndeO}O_oW>pjER=zu>=&?J@5r}>f?k$p8mf;MnY5K^K2NdCl z?r@9N#yzcbEwTd1p`!z)PF`@~4`y0#u-F50yz!vRlXRIaGPRxJK+T#xdsdqd+%z=P zyHVc@>$6NFUT7l2C4Ys?0ztjO(led0MD^bS%IeeO_4y2YC!c$-2xB#5%)oD<l z+DJ9|D5S!C7lJ{T+Dq`k#3N((#7kO zc?CN}E?nqa2%M8-4V33??lq5t6AlXi04{E=^8#*DgI^9r#M9O<`b(c_8=s>>_5;QZ zKrnh;+cH#NqPs|`f@PaPwhhB>sDMGN0_8GtX(bmQ_dnDAaaXNxb z#y&{>$uIh8X}%txxoSP73^uw82(tVP-v7@wC_&CdO6&{0ETY|(+K%Hl1ARp~3~hK3 zyf;v1)Wu}N$~N%Dx0Me$*(q_w0ETjO(Hw!FF<6sKp3o0;gjuALHWQ4pS^Z3VRi_`v zrFxLrA|Ig;JCv6#crv?V4M>{4!{t_pfy)HH9IK4DIxMUSl}jq^dO4X{l$%UQ)_saB zBl#*H(8IH>|498Yc?@U%lkf8k`Ok~9T5(Jk3V>5y*cv!ODh*+asXxJ{lj{A_PnVNu z-&ksyZqz4y88*X5p+~B> zCHeeGMa^6NRf;(ndE#4#IgL@`2InON+!Wj^+hF8KA!)!-D<)Az#pC1jN_`|;n{P4rksDkKZYv(X1q?tK&wB$sg5w@ zVpxSpgf!Fl!RjdspNbjcIVhivAS0bd7g7qOG;*3mPr3&#LSj5dvdL|}&DhqfM|Gr( ziKsd7;?{9`(4KaqUvA=L%~O$7N`iQ?*6w+${oZ*iK^X0bH{6sQ*KgT#jN?S$(Ft=g z6a-ebH5S5P(61EQu_iV(q@sYHXR)<9+Pus7+7UIUbY`<^Id-bAB{W1l4C^gGb@Mfm6QcF26g z^YabSOJ_w6gDG`{dwNg}dqWz+4r&JrdcdAB_Dz04C%T6b({S%83ud_-ss~Gq(-MgY zJZ%|#za6e8OOM@DDe^>#Q~!=kEXxvceZ%f{8b%i8>Nkc>TEb2J*{*Y7FhBKhQ(<$) zs-m91#Utwx+~dvEC-!)mWqth+aUkL~@(etwPiXV>nfS_(LkUQ29rhH4aPD}IN(qvx zO`4uLOymbP@TY)HkX4h_VW`8{h)lzLLb0_+$o9S5Q3mDQk4%@fJc{cGLF%LQ6=`eP z49ModtHQZyF5C{vMp~la0h#Psyl*|i#WiF-rCgfsz1~Sy;!Dk>kxXNwlqXT2S??u7 zv-3)<>57IAgUs(qjVBb;M%MCj9!`UvQEl6Q9AG$Q7-2#5ku>KQ?J7E{5t8AjN|2?N z$8%*)TsZE-ET^63q^nt0)L3Sxpre{ke2&-kXyQ3V)I;u-pCImPJ=Hao=Q#x?(z469 zPksy>=918`=y(Ohx5eG|QwC}00-lm8*KTf}67e}s*Q3*So_7mp4v$mopQc_8)?YR@ zUR)o}>OCpIDGE^Omjw#OrUk+mollt4wz`+5tzz*n_#V+D#_cxx85+zvd`y9`87M?n zAnRprXfy?>j0E%OjE=sBh9L1u>C^l_zM1dN^ey`O5P;pK>mXQknwm~#GLGe>wCUK>^n30dRiD%NOK;5)KK0|ub>hcASgiyk-O`BdT zY8#~?1va|vD|l16{rDlz!0?HlGGXII<(vPNkUa ztA(g!($yI=4l_Z}V}qqyH!mpWt3T}0Ph-u&TEsgpQ^f#PH=a2}Am6ZI2^MM~W2vw* z90r{(E18hjmFP=vo*)jJV*%=D?*7fdDNd&b`#DmXgxPY!pYwW4Q`r?7FLO(lsMn@~ zbk+x_pa9pQxW#kefkj~-P{j;=tmRCB?2c?<8Wnf!ttX?N70R&4i=y2P^tV9_8+Q6^ zBe~>zsA|l<#WiZS*46oK+8sl?E!^d;jp=l`wB`WnR@D=XD0c-_N?CKHn z=xbsvscdFi;*ydLhM~88I)Xa1n3L}f8aqoxqUD=^wyN-lnx6^fA_EW8|v3R$z!IcDzri7PtEzSca{2x4JhHldl z4mIZmZDagu8Sbtp$2Q-L9y|KXZ^p-R0q&`3HtXW3_aS>VZm{r0mHZ(WfWjH5BfOyA{>Bt(0LghYfbYWx!Mj?J}>88NmZMKNO1-Lc45}sAa z>d!Q)wr@YOf5{OnOW|?V=^fkE-?voWPI8M0fSuxuPuJ-rX|U>6d;(H_wF}ulPeA0X znA&LntW1cVk%UUDo9ita!8_XOH>T;+XUu=57FZ}^W&tj)O9JyzsH6d`v`4Knb}|`u zNZaX?=mOn}#;4J3ijvI68f!S#JslBWU4&Mn4p7<5X|2u06AwdKp!E0od%?H@rC&DK z(e7p^HEgB8LTsx9$>2zqOr;WB{!~<)l8;3hx0|43Ma)`~l^&e3Jf|c=ypZOR zUi|ZZWkprI$_d5*+6j3FIs;D$z!(zo=5m6++SAt*Z9zD1h+i zU6u1TG?|!U)iLt`l;GkzAIoAd57YRK@TOVWSyaHUnpINh`udUBOrBh%%Je6#?u6Xp!q3+5HcC!OV!!HtwB(N4J{_x#Vdb)@4L<*uM-SSZgST{TJk!pP+=@}iLSXr8GT)iMpHDRtPr-K?1#MA&5V zB`AxqG471A*8`C@T}>BQFX;Dcs&={&ySQ#whpx@z=!R3XPJxob%$(Ald*M18VerDhk$2Lsxqf;!Xi!6{lY?lYNl6FyYNA)?2E0$CVd>>3c4BdV16vDTq86*Ow-w_TB zQkCX(9Z!jW_o~qPxwWkec8&oGDt7P)k{R6`VBRA}n?JQ}8)7ePI)Tq>TWU<@m{$_k zE=VQmQ0`D-#WIcK0%Kz%*@F=K~cLr?vEyC_RG+<*G>_=C{? zz_p-b>(ep?#-VtQoSl(9M@t(6{vFJ#H`aD%_}1rcCpiBUScy5cMp6}H>|64AUX?FY z6yZo^$q>rz$a8wFT;IX+;ui2bzieT`+$My~TqLedx$aEo4X+S=#}iUuSTzGUg}u?t z3P1&iYVZZb`6zVPXt?LLhWGurO-hs||5(Z?sf*CKl)t=@SULm6`Y9u;W1Be>RwjZ) zbge|pR?A zSZhQAQ*FnY7^#4uW7LKOC_61awtLed7z?%*UORt#!vA%lfk2Y^#|0F1DV74%LAWD3 zL}|IgaSjrXH@Tq2xFfMlTc)>V-VcHAT?2~%}6&E@ggL~uG2)mh?2u34XcX1Cvi*EE$ zsbOa*PF-N7eHzQvCU`C7B=I={q{UftrFPTU_&Vm-jg9N4HNkbAFRoL=V%#5SS)D|; zrsm$N$~zBk5p<)}zz2rKXc;ezagWUHxQUOO&VovaCI(5HARdafu26>FVtO17UG603 zLo*<1o*YrhX$hldzN3Hj6+>;=NX-jwMr=<{YfIan#|8!`4!Ip(F2%TfXn^fSI##9Z zE1S4IuH0U*D2d43lND?-Tn0H7bXBcZKhx+q9*VygLB3PuyNTt4keU$%y!dzt)kcKVOp_m`*n7i)9!yHtDbH`|CfoX|!%QcYKAP zlV7l(UtfF~Vc+d-p;1wdY2IFwazNuuTOH0l2(Z*&LGcLDH|1Qx7YK43M&4SwGQ5a< zczPCnWq&KxjnXaBZP2aKOhVBv; z&}(E|>m+e6;dPXBlC(Y3N4{wqG^Cv1$S=y@$6v@d#}~^l>6`9TbG^3TvU#0&pgeUA zWf=-Wp=*|+`MQ5MSQz*xxBi#`XzHqccpXIIBN@U%_!*Oy78-BwZqr zW6ihGGycx}oOff>`)#Z6+WKe8F6+8w`V>pvi@@e1-<9{t@ecmh>I~-q=elR+InCxs zC##?4Q_bD_S=;Je)w%xWQ)hy-uQR6)9(Ww-pp2ZWRK=ITLL}bwF&oOzGC0H@EBZOhBm7!# z>0N}I1ut0>f-j%iM{j2ciOy7?SV0m@F@K;du&kj_koKNOsGV0ZK(=h4JWp5wHd?S91q*qOzYFj6OgLFWiz{5Mq$gaMni{vh9g(KX7Z~Q zCWAJiDHv`gK*@G?)ayb@Wb=4grPn?)Y~UVUfMmv)#*Tt{%M)>pDG_8L9M#GVafU9S zF9mr}WvYkSAG{pmGf;=6%$}{xJNxCEql)l$xAV-452GQ#0BH|dj+fE}|I>Y*b)lKTvh1yfhK#EpWM-(Gkg07;wljl$*)-%{r!-kQWIO?cc;p5|JT&E_M3 zWrM0y8Cnw?z*X>hD`>gAZ8U+PKkq3tM(-o6Kp)!=XO+s+51sNX!!sk>n)x z9Q%MZngi)Z0L?Sl)UXBQ1!Y>@W6$z_YSnhhOGj-S@R~u|J{+@IcS02!r6)iLmbBFj z&hLwqn1BsBkr7quVMgd&K1^Hov-cAmUH+jEKgJ-cmFhu^kIe_1NjX{kkpR2(T8cyS*SOZ!MS;2LHXr)V>?hNNYhTSeqCt1 zSM+;So*7vI(wq%6et>-*f+V|E{8IXLz`%UIN@DK%}%}<2D(x z_!eGxb*;OQFa5NPz9m$4SvZA5u@RA`1n=;iLOAK@1Whk_LNvHtZ;C7w$`=Cp00JRY z9lJ)(nLRcl#~w8Tguq!2OsGDF%4$}_$Nity&=gj`9+|ADMGaYe;Ah=r*yKyCwt+D- zd2Pzk#B52-CVUPHU(|X8l`1Y6Qg!4jBv~_o(yIK^T&?B>68ilrk1#>j^IzH*+P;jW za1001!3VBjJ$?|p9CcZBMZ#uPKe*WbF+C~Kv8qy%%KO>%NKwozZCMY8-H2d)1GLwG zy~nAN93)~@#Y-!Qbe>>hP>OBZtVHX8))A<6{l@eqyN~T?Q@S@xmKV+K5Q8mP5=GF& zsr;4-T3im0)e=vAb8l_Wz%Ju8Y4D`6$^CS8qw32b9rB9}$|P#>O9y2BZUsXxn+#Jb zLn~v6RuwoT+5mXcK<>#2W{^H?rqJVp8Nwv?I) zZ3=_?D5QRE+zwcG|8+(_x4E4$Q>vJ^q8h0*$xxex+u(JD7t+bYXF17}{O#dtq%Y%R z+VodtdLN{;O!F+ji{mP7O&8gvRh|k}fa#L$Ox;;9w0&K3p#{MKDp2 z`61(FxR(N;g6D_mToqED%^nLhO13*3wwn^@(pfiryG@ZeA6Hz}nq@54>3(NS(^SWU z>m&XlNi$a&9BCzy%j+<+uV@AJIt89&c**-L`@eXxJW-0$S#MgvHegZce$A)OaTyh% z#TCl04$YKE;}^o#wW6~mq#*XuA8me=9^GX9#ZhRV+&2v0gBAKhXU6-{Z`e-vq>0N) z`3cfuMIdK__uIk-8OZ8XKv+(d>?tD>c~-XB=D1<&fHZfn z|1ih`Ie}mAyo#=&1NT=yBmDktmxu}<9alkdZuwCnRSB-E7H+;`&m%Yc;JwMEib=hW zjoj~_&a^M1)%k0zdx*PVA8%hb0|W7uH)Vzrfr-mRsIC-b2vVkf5H9T&I{5m?Wd~=I zcwc0~YR`%#J}S$|grUX|kwNz++FhhXkMTuMc$gTTnDs*1H@L-Z&nS}2*`PZC`+9dl zVR|^6mTgc7sUB(2(V6|~#9@j#+sRvA1p^={Gns4*kswZ_$1nsbyUw-p4b7#8SjpU` zKSEsc6JEdG64Rfr6x^L8ag4U4Dxtx6DNuin?rTwtedb9VB%(-Jo+jvUFf9|)RAmM& z-E}(*aV`q`2D+DJTiQt{G+c=@?=h{R~shc8)jQYI@%}}#+FX8R z(eSM-SH#I;5$>Wjjz1hvfmyiI^qbqZBka-h8o`U1Ng$$sIpIDBn)BT`M~vMg&mdX1 z=WW*l4Jy6gN`tZaZc%f4-)0cC*HR*IXe8{jn;QzOU}kE-J?e?ZYQ<@p(uwkuO1@rn zTWXX)Z+i82NitJ83uTcgSbxJv(NO-O^uYFk3ZASLo}|Y?h50w7+Cp)V&~h9{a(iPG zzS5{8x$tdSI$-oxq=i-B+tEjI=&HP0kve}PbUVIL#C0#`ns6S=ytkd(y#d(AY!dW^ zo<$V77d5yM94v|}T|TwO0+Tibs(_7qQghSddjaULYy4iQRYs}hc3!#pd4A~aU(VdQ z4Dzd|bmi_sVjKZ}_4ac+1GZJy4~*8LJG=5)cj_?18Yh*{q_275c{ywmFBc_fIznNv z-;qJ`xxK7%el3(0iiI~Y8()*o&l&~&@Yk7R(^Di&S$stODHbz6Y)!^?zpHDd%AiW$ zSpHf_&X#BdS-gi(r(ldHX9bG5=Zxjlvp2U4{*>*cqT_!f+0<-EG7k6E3U%ZIk?1ZS zd4l`wTZr`Z9YV0SrPQ~N^$p!n)?A?Q^7mnG0|;8im?wlz^b6{smd?|WZd{2i3kZ0H z+|>;PWn#8u7+G(CF2a4# z;p(lxUJ>o;VNX8Kcb_@FA$mBU@)h81<0BmaQSakRz#iHi`yi$2+=XT2F6S#vaTM>> zx6)a9ZquS-L!w&=BqaK2M+16o)QPY9Hy>vUC3@*nOa|nE%JyG4`sJII8+YhrI>>)c z`Bl5Z{PZl@cgDGX?Z#9z#BnYe&}`)EUvw;j7-U{TSdpWTXeW5MQI6++!_o{(aOt_4*A*| zG5Lc-qlD?aF;o&euGDc!=U%O_JX_S<2rf*@1Q|drfI4E-aX=|Mxm;b0zmxe`Kmz5I z*GubT4@J^=pGVnwh=hor-7B?uUaER?2NB*cb{`r4*f9&tQJe`T-464W(%FGi@d>k` z12rXDyMi)a=g38r+b@t*TDH_zy<^*0!DX+LY&DG(Nx!_Qll*lW)nuzGjmS$^3{w_h zJ*>!hbI~w1hGDmT;!on1ROOSz$a3WyYUnfYDDCAnO476f_OJ%S$x{+zePIap&vn%; z9XqLKO{OeVbVG|JZ$xwpWQQycA)knJh%~xw?ofpQH>x$tI62hp9uR!RgO!}@1{r0S zM=u;wc`Cc?V2s0w1${NaVSJXo(0iM|qKBl4fMp59TjP&9c!|;2)Mf=UJ*=D2?}V2- zaprQ)>Hg44+)yzQD2U-QjuapNu$4@*V9x<%3czPTHD zu5@L-~@b)p=uVU zKwNRPZ?(6_Yt(EH-yqTsEG|DnJjeE_Y&fWwI8SGNZKSj1 z3auN|=&5#6>sESlCm5Y)|CqLBw<<%RE z0N5^CZfmP_WSjo%XYR^-D8D_;bTtg@km@mD?$+&y8hUwglFs%u63 zWEKiKz7x?T8y5?k4l^_L z`|rOr-)WJ5Gcw-`WX;@7-|MUaf7idhmsh)4J35H{u2}{AS@Oyx?`Zb#?SC;Fyc zv%C{;|3k*c{ZBoPcLwKw=&^CWTl^0hfScugp8tJ3HZG2T^kwE``GOmr+YQSUA2Dod0|ld#C>LnQ&ULa0l5EN#Ur~|IF-}IkRW4-yVKl6*WLN90UeoZJmKvu7Jd~Fm4W>jvxt=qz@8Tb8_*-xRahPC{K(E2934DfaK(W9-i(P zlq=AeJUQi>+nh9A_>RnpQA!o`;rKflK@PhCDscV)z2V7ET{)%l)44?93r$;$!VfPd zONHr=QmI2{NOrjNO`@2dqq2XTWoCI zifB*S5?an(V?>uReU0lx0;kRqZ3E2!ZbIAU_jFUK&FX3vMcOGIDf2R?$%gyF+ZynwBz>v-O!__?5T1@ENEoSRjT_j z3(f7Qi@g|(z>9qG?Y$j;?mHvsgRxoI`L8Ag3d#YF+0Z*3k+yyrF6s(NSTV>>x)g4= zR_sOO>vS_QZ@mKAP1h<2IT`0y!5;|0d2UwZ z-+55YxBRA=7m)16Dl_~F(y{{2ZwoW(W~;Pk zWV%A{qfqpbj{YpS6;Q*IFRR+X*E1bVDJH~rPH7gGTG{is8)8nx*$=COH6n?O10req zPZ>%U_`=Vyvp|LGnEWCWDf<~Lm-&Fg0;*^}cD1C8ZW)D@mCRj$W@5iI;Y}K#l&e$b zguW{zG`lEklO{>z*_sCqxUK++i|;G1I$`4bvf=w`%h&iw!gq3JMknm}{(5bK+F!+0 zRqYLVeu?=E+Lv#epG7N)nW2ojyti{?m8!kt?P|;!VoN^Cc~GRW1O76O@D*ik z>{nLkpTk$D7XI|SSx|AR#YPnp(Q;-G8uj0KJb7?MFD)Fm}j%0ev?0*f4^!8RoL?Bx-PM(>wD2|uOU zoM+4crK1P&)_WAoC;I}LQcDwsP)N2T!GXlV!z7xbKy8d!-yw7DgWTcv)8PS6qGxlS z^jOc>NPmwS=-9kK#dFkp?{3|MY;qq}q+t6cT`!u&CAKPPO@hU%SM=RpK0yUfypG5v zqsL@{7&p6LTb5Kh-s#8N`}m1~NglsEE<*nZ0)~D!F(7eWl*5l-cZ{1S2=+4|=wm#v zUhZg&2T1a#pp13%B)#_l9S0Fo#JGmBb3!R$eL?16k^qH(;1ZTVQpot#%Wsi=W0LE_3-7p%L%O%xgfI*vuk9uSb!53_P|$6@D}4e38@{0diyAGO4_ zNy8LZJPuiIq<94qSHXBYp)vYMrT-ntGE#gD4aV6b@%2*m{ik?A{99c9G@y5v)mZ_0 zQ5wOz6cJ$p-YO^5SeS*b+ZnzkM@I6ZRat27hT4wOd|}dUZ_-myou7=kL9>RF*qll~ z>@b}kU#uJ*cUTJ?ts&F>77A$gG$9X$XPdCBE;m`6I^EN{L&3pB&R|0RmSArWK<=tg z41KGYO-n0KZ!h0o6$`ejeJ|3eE8sD56co=ZrObDd45&IRdF74(`#eRGL3tY|^a#+s zl`I5}fI!)@X>wlh&bF4iY(HPPRNM6^RbVcg%e0TP4xSlPt2>p>Psoh{WLrGq|LBl= zn+j8JsF6-KzjJYLaQBH88JH!_x_40^+a(IB%EGxC^@W0rI;j;==gttlhj7d!^UZgd zyAO!cu+3*4edIL%sndRcqugN67IG=6YC;lzk=gl zSuq`1aNKJgpFVfT;83>H|G;QNfQZjjjL9^eb|JnHuV*9M<}-VIw!9(Ph^)f(q{2Mm zh0Yp??8^zVim4}?=OSFJ5?W{I1Zks*L>CY8tQ%sNK1m&9g<`uKBM>`jJ*x-TFXyw% zhg{HLg<(|Z^PlHys`U2KF{I+{4tJQ2X5S*5{_1KGd6M;(eIxvnk=~~yny@Ix+VCqO zCJ)8zfMG$ygdh${K`PEW88=uQy{yRs!x6ew8dRNFSu*7dlzeXT{uF`B=1dS^XG5JM zF22+w4(k7Xai53Q;=UU}OOe-LVVf?_&YeF;gfn+K%%zFq)I%!Ir$Bg!7??uDhMqeZ zc9U`nL>3mT&P16)DW*>0qyTuOC^tq1RD_I?d*5}wNj4PX-w)6ZmArY<0$}`>{w6J5 zFj4^+(WD6`p9*oJ4qazr%~33R$d<>LrZmEI#*EreSy5M-g|baK>LF8t!d|~X0f+G2 zqHJYd*{utnTs72|clV!C^@HFi56J_=m>*FLqUguS-UN@AUFN1nHuro~@nwBN#s2m^ z;c69|97AO@JK@YanMk;Gb0W1uCpG1OnhEup4Hcz_CVb?~=WoRG=1~-?raxrJJ5wF2 z9)D|&@?>N->JbN9JLhbqX$-;kI%>rBDtP!2`q6bQ_613MCRoT`=rh~lm-!}wFXX*x zB$*$_ind<2iL)^;OMOW>h9X|(X6Sg!Im3PPP8Ej*)J>uUP{}wNQyaY8LQfFb@U0V` zVp$7iZ1PyQy?wp`7{ncPZaR*qy;1NXjTzuZDC7AQ5T6U5Arlw%BK2Vyb2D5oq(H}$ zH-gEp)xuWj<%2QBIt^|C?L-!h2tIawKB2UV5JL@TUP}R4f%@}_T{3n^cMekpE1eR) zERZ!nV}iVH(nSFlovYlcO5@sytJMmA3VzDZ^yv%ShD?ec)nu6I)T;zu4HQQv!csR= zXS;BT#ql?ims11yb&^I?eNwH(vIMQq2VMQ1|E-EbuSucFASAc!dbS#&qFFXvLp41o z+4i1ox^0y0-5H5CJ^s3ckc7%pI)w_K%ii%nJI|#w_{{HJRmHUmnF-7U_$*Q??_eixtP>pW}Tp@fp_eqq%R9 zOJy}t{#E2B#=>GSD}@Qw;cGuqbxvw5?{*H+-< zwAEfid;aohL^iHu<+VDe~ny`sheB4x!eLuSqm5ItFpf41~7Y_*Mn&n<@mqx$2b$>%{ z)?A=0DnlbdBev_B!PwB0p-m0G0#A2i!BGHSEK%E$Q})5s^o82UQ$)*^&fB?ukM}Oo z%0`<+XRuAOS&OWQ7>F*5@R$mjo-lE(SSs6ZnP^SFVTlgxh;W`om-ppQF1*GSicWhs zt^{6Aw=A1vtJSW>Z!>K39ta#jsAMC3BkLJ<#yq_*)`kTRGcSK4RP}Ad%u)#k2)-QD zcs`wB+9%XU-WTzjGBz`$mouw=ZTA4cv`D_sins8#-)`BJGN`iYtQ9md!>`at&{?wXdvJ(}z+VUu{i=+7@A&!vL~T`7lv``n<2v7UBBNv3G}(OAx{z(E z!^mr@0jjC0nyDrtrsZ>LF=jEKd|5W0Gpqr8-tL7v?>n#E#Y%#c+O5U9YvjPE}YjY*|M(onFov})+!uRzD-;7d=9ZC?Emjg2b>sKNUV@J-_W~NvZ?>K#a zz2;i~`DXcH$}H|d!->Gfeai#!sqLD;`3FZCXDFjj?yrh91RPm?ko_DubvQs($Y>?s z>o0xic!(y><_H3HgfoleafidZqxOaMTg0cMHu&;;4sj7x%Hl`Kd!;%pC-8;%OKKHr zOGq3NAF~%T>Hl)8ZM`QZb#OMkQRw@do#cVytUEpj^$xaOt?M@imeb^~P8BpD_D8l| z7wtaH4f;5(Z;$`Z(#MeOMdEP? zNLN~5PpJ3!Me~0nH3agj#l>qVG)Tt)WCDVK z#Yn227s}n!A4KBwAE58+DfD~PklzWzMHLw+7$O0IfMF0Q908Ru1A_%g_un=D7!8T} z?Yz*WBZVJ5lJW&*(n*4+6V^@T7}$TTl^#MajkaD2^ zXbUA}K>wk^5U_vMgM+0=Yxd8!a0v9jXi|UJ^K?f!xnSIXoZA>U`IEjMDgDvMVoBa{ z>;a??so`diCArGavI@yru1HAQ*-OD-V1zvcjRs3dLeXGbd$be^0hX46BkZ7Z!2ez4 Zr?Yu@l3e4*g218D(m;NGRUI|p{{dJmCyoFB literal 0 HcmV?d00001 diff --git a/caffeine/Assets.xcassets/Input/Shots/1-shot.imageset/Contents.json b/caffeine/Assets.xcassets/Input/Shots/1-shot.imageset/Contents.json new file mode 100644 index 0000000..c556d1e --- /dev/null +++ b/caffeine/Assets.xcassets/Input/Shots/1-shot.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "oneshot.pdf", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/caffeine/Assets.xcassets/Input/Shots/1-shot.imageset/oneshot.pdf b/caffeine/Assets.xcassets/Input/Shots/1-shot.imageset/oneshot.pdf new file mode 100644 index 0000000000000000000000000000000000000000..ea2ccbc73b71f69efe58ce0a1654ba539e79326e GIT binary patch literal 4063 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 literal 0 HcmV?d00001 diff --git a/caffeine/Assets.xcassets/Input/Shots/2-shots.imageset/2-shots.pdf b/caffeine/Assets.xcassets/Input/Shots/2-shots.imageset/2-shots.pdf new file mode 100644 index 0000000000000000000000000000000000000000..d50ba1fd293e73859f77323c32e63aceef51aafd GIT binary patch literal 4104 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 F{y!=k8h`)* literal 0 HcmV?d00001 diff --git a/caffeine/Assets.xcassets/Input/Shots/3-shots.imageset/Contents.json b/caffeine/Assets.xcassets/Input/Shots/3-shots.imageset/Contents.json new file mode 100644 index 0000000..d6a02df --- /dev/null +++ b/caffeine/Assets.xcassets/Input/Shots/3-shots.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "3-shots.pdf", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/caffeine/Assets.xcassets/Input/Shots/Contents.json b/caffeine/Assets.xcassets/Input/Shots/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/caffeine/Assets.xcassets/Input/Shots/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/caffeine/Assets.xcassets/Input/Sugar/1-sugar.imageset/1-sugar.pdf b/caffeine/Assets.xcassets/Input/Sugar/1-sugar.imageset/1-sugar.pdf new file mode 100644 index 0000000000000000000000000000000000000000..72211f3d8db28d716d88a391377bf110bd2e2dfc GIT binary patch literal 4034 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 FzX8B0%mM%a literal 0 HcmV?d00001 diff --git a/caffeine/Assets.xcassets/Quick Launch/quickMedium.imageset/Contents.json b/caffeine/Assets.xcassets/Quick Launch/quickMedium.imageset/Contents.json new file mode 100644 index 0000000..d1e1215 --- /dev/null +++ b/caffeine/Assets.xcassets/Quick Launch/quickMedium.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "quickMedium.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/caffeine/Assets.xcassets/Quick Launch/quickMedium.imageset/quickMedium.png b/caffeine/Assets.xcassets/Quick Launch/quickMedium.imageset/quickMedium.png new file mode 100644 index 0000000000000000000000000000000000000000..b68d7016525bc2993aedda34e84569b569ddd159 GIT binary patch literal 1870 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 literal 0 HcmV?d00001 diff --git a/caffeine/Assets.xcassets/Quick Launch/quickShot.imageset/Contents.json b/caffeine/Assets.xcassets/Quick Launch/quickShot.imageset/Contents.json new file mode 100644 index 0000000..42cfd59 --- /dev/null +++ b/caffeine/Assets.xcassets/Quick Launch/quickShot.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "QuickShot.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/caffeine/Assets.xcassets/Quick Launch/quickShot.imageset/QuickShot.png b/caffeine/Assets.xcassets/Quick Launch/quickShot.imageset/QuickShot.png new file mode 100644 index 0000000000000000000000000000000000000000..14639a7d444d0902c726822e5fa5d6e193ee78bd GIT binary patch literal 1684 zcmeAS@N?(olHy`uVBq!ia0vp^ZXnFT1|$ph9?;Zqle1Gx6p~WYGxKbf-tXS8q>!0ns}yePYv5bpoSKp8QB{;0T;&&% zT$P<{nWAKG$7NGt1vDTxwIorYA~z?m*s8)-32d$vkPQ;nS5g2gDap1~itr6kaLzAE zRWQ{v)iY4C<5I9GN=dT{a&d!d2J&o`GD=Dctn~HE%ggo3jrH=2()A53EiLs8jP#9+ zbb%^#i!1X=5-W7`ij_e|K+JGSElw`VEGWs$&r<-InV6JcT4JlDqz|%0A8HHGx%zPT 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 literal 0 HcmV?d00001 diff --git a/caffeine/Assets.xcassets/Quick Launch/quickSmall.imageset/Contents.json b/caffeine/Assets.xcassets/Quick Launch/quickSmall.imageset/Contents.json new file mode 100644 index 0000000..fd86098 --- /dev/null +++ b/caffeine/Assets.xcassets/Quick Launch/quickSmall.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "quickSmall.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/caffeine/Assets.xcassets/Quick Launch/quickSmall.imageset/quickSmall.png b/caffeine/Assets.xcassets/Quick Launch/quickSmall.imageset/quickSmall.png new file mode 100644 index 0000000000000000000000000000000000000000..be17a803de5dcdb30a8e3986caa7c68d05c22ffb GIT binary patch literal 1823 zcmYLKc~sNK7XBq5p<$7I)ng2iO_C5cOG=>Zd)P~mVhkZ9Kb8bYfQWzr*_B<8!{S3( zPeG)B^?+=l5!~>-7fcWyDy5170zq1dEYBC(p1wcs+4vJx?r7*;e5!%a+*tpk9A6E}%Mji+%C z(KI^9Bp^5Mk0B9Y3;`K#>u>3wr5sq+3iHXGryLtSzS(Xuy z3=Ss=kHw~^r(@EsF{~6i7H4m7kF~VIT3MlG2sHZwlSAR6nQWs&ia$BrXl!Zs^K{@t%E`CBoKDU+EZ(_`S%wJJNNe9+Z3kR9ylg79{C zwZqxl*`cj4H~=uMOsyRBb#+!NbZXJqLgcGkSOn*3onu^UZh~plsG-bJan-}$yJ(!) zba%5rC!mA5=Ua+O@1`v|Ary1Zf|S!ba663~{oV-Yrxy43)>-t}bUI(>86%<}RO}lZ zR{t0Ery)rXR9d;=`-q>^at>*l@o1drqMl<-?$`1%ncJ1$WFX`L(L@|{_ z(o*QvtfEn}Xu)LhMSfSq4?5ozu4TQ?{&$PV0Ls?q-l=NI1;}yr_rrx^QOZm6y+#6G zs4Bm)C{c7++9d5A316p^NmG*>vd8&Vl2-&905C>}2I00jr2&AvzPFomD7SIFVfxB3 zcfH9=QT?%xm{$$Vs*5Od@&vQo49R6~g(*^NB12fcg(~_Cd-`A@Wecfy8TJ+TdB|(6 zAi?Eaq=EzEMLCX~2k$YSvyG{aI~qnf+0|Wrd#9->Vio4f!deH291foUM-)W}G}VIV zyWIT0E4c0x;vgM@ZUk46?ZiOz4*@EM5RlQ^P%?RfgOv_Pk@eYn~+c zdA_e+RgIUtIQLsURP`O4ZelFmB`(sJ=H5{ki+*ID4BxTa>pjj@kpc`J{c7s#w+w@v z>=8ekwXA9AzcWQXKZ&Cl>bE_Fp{m&yL#F0XCREdv^1{sqdK&e>O7bHn`I#%%qJhG;IH}Ao%cb zf7m!8>q*m8qfvdNI(F5#*fS0nl1|u%J19Cp_p44D+iw%RKRnl*96Hg)*-N-Dx397Q z@iSPfW!s)AVfjY>_6Z*M>4}_M$TQzMXy4=jy)7%Z{y_MXSz7FZMX`Py)y@jH&aaEy zj=IN>#l?1N&YXG$eW95-;vRVKM8O%{3iKmK*jOc8uf9oCPWTq0I{M0a_+<7GN$`+x zGQq8BMWuzKZZ`4IL?NFd-(Z2Oy4Aq1tMu|?nYN{_Ia}^e>aFP%-#ccUvxmAndmdGw zq1+3=$mMbui!`6~wEk3pyWDLZBDm-?X1M02yW@e!nTmAv4g>>0B`W*yA(fuU2ndA5|UAHslier!l8z%h}t7hT9+>QI-~s5J9Ogaf@|%Ns`|~y5`k9 zyQCA-x1^14suG8^xRfx%C5G{`(xR0F)vJ|>PA!~PJ5dRf`gv`W8DAz66}Y-w5^2{$ uGWz32XD_on$0Avt9H8iXPGmlW{sMf8N73sZQU?$JHE(yKTaU~6-2VZ&xgaV4 literal 0 HcmV?d00001 diff --git a/caffeine/Assets.xcassets/Quick Launch/quickSmallPressed.imageset/Contents.json b/caffeine/Assets.xcassets/Quick Launch/quickSmallPressed.imageset/Contents.json new file mode 100644 index 0000000..19123bc --- /dev/null +++ b/caffeine/Assets.xcassets/Quick Launch/quickSmallPressed.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "quickSmallPressed.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/caffeine/Assets.xcassets/Quick Launch/quickSmallPressed.imageset/quickSmallPressed.png b/caffeine/Assets.xcassets/Quick Launch/quickSmallPressed.imageset/quickSmallPressed.png new file mode 100644 index 0000000000000000000000000000000000000000..1fb21d3070e5972c120e89124930b63329b989cf GIT binary patch literal 1862 zcmX|Cc{Cg77Eh>U?6KEU5!)aVp;T0Cu@g+FrO(nN5{V@uXkuS#iS5m!WvZ51Y8xii zs-kwSF}3ulqO|pzI32|s6;x>(=EcmM{&Da9?)~ofyZ85&q(P?G=v0MhPm zPFR6;ITdkHfsTi*hqY*w`^?I6^cr5sW8B zQm81%&cFx+Oo>220xdA67#f;LrnsfhiGC^G{)Cih0x|+(XDeaDv=#uw5)*M?W^4>K z!J3JJ{Do^RIG={$5b$3qiP0!X5XKjbj-wO77BCB#Da2L+Y(tMAS!11C{&_6$P!Mur zBF!2OXD}ErhB+*b9tlSvkx00y8QjdwM37;UkW5X)F-@omI;RkSV>l5L2y_Z9krGD* zpJL+haY>0N2n2pw1pZGILA&s8{R*6KjEPhMO}c=Onn%Z$;G6O&XtZwv*3}X0?u@oX zAT2FT%wPxr;QO+qvVKprgIs}Kll(3?4+Mo`a}~qLH|lG}tkRyVYj$AqoXZrPv9g4vd|kIY*kJ}b@O3*blEjD{Q+`Gc?xu*}?;iy1 z`Sg#MDgAU@VfpAz@ zqr)HI6rXpMDiyFHvFmafEi}ZW)QclkQizL|F!SsUrKGi?<|DAWe8i$y+l0_VdWkyHqyAJ-Y@alcT=h^$iDPtK@6R7Dg$ezx%v*$fRsgjFF zr9vg?tl{v*HwK*LypHOhl`j_jFMT89d6UZnT?>z1z3aSWpeATzuwZGCzH0Qf1~oP> zbLInwCvLO06ZBOia62+QX!6$&g5ms*<`$d)0Kjxk1;}i+y9xlDv3GZJ@MqR+SNo7P zoi!%y_8Vg{pjgjEwGvE|a|(~t&T;4*mmx2qdHO6dk%q~zLGebF&7p@6S>P~+CMh$fKpjGxt50QcV|DD?(fY%D0N>yOwF81yRzcN{QPWq=OkmKYPHH9 zQs$;BU+DDBY=oDzFiHDrU1;}{TgJsAda;^>9PQhH9bl7MI$(eFaCDLlJtjZec8#k{W z5v>XS)Dg{v-a0(w;5f=%B35$$ULEBIaW_~`V@_0g7kN@NsUt7KjicMq%MydaX(9_* zfuX^C`KDlnK6dYJ3tv=Y>!Bfl4P6fnPLoc{9$6{CTj-S}>(q?I6Q9e^6>}r3v}R&# z6?JrRGsay0^{fD>pS{Ae=pV(PBBNp4vps*ZC1IyrPMQ$*OG!`hBWS2zX)xyakiWOTcylFexv1F zt^ei!RyH=YNlTHQ@DrA5>jLM)9ADqO*X0?q$BuHv*~?)N1>S15`+rxE2;5n$R#CJ!iiu=r2Y`PoHa#q!w|Mcr$?E|>jk&XFYbbP zu#C75E)*Dyt~e7!zA&DP)!1fb%k8mk(lxAL+BGZu(IVR?&y9xXo*ut6uZ}B|m!5dT z-au>2vXBLDyZW^H>Q+LG-bE);Hw?9B2Yg>=q-@Sl^uMpmu_2WU&40#6>-7SAMJ=Q;qxMCo>(AZU+llRXCFlQyDLPF6 literal 0 HcmV?d00001 diff --git a/caffeine/Assets.xcassets/TabBar/Contents.json b/caffeine/Assets.xcassets/TabBar/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/caffeine/Assets.xcassets/TabBar/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/caffeine/Assets.xcassets/TabBar/consumption.imageset/Contents.json b/caffeine/Assets.xcassets/TabBar/consumption.imageset/Contents.json new file mode 100644 index 0000000..8d49ee1 --- /dev/null +++ b/caffeine/Assets.xcassets/TabBar/consumption.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "consumption@1x.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "conumption@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "conumption@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/caffeine/Assets.xcassets/TabBar/consumption.imageset/consumption@1x.png b/caffeine/Assets.xcassets/TabBar/consumption.imageset/consumption@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..124ce39e2cecd27cefe7fd1f38c753fd4049bcc4 GIT binary patch literal 3237 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 XD8x>(w}H8l00000NkvXXu0mjfRv!(a literal 0 HcmV?d00001 diff --git a/caffeine/Assets.xcassets/TabBar/consumption.imageset/conumption@2x.png b/caffeine/Assets.xcassets/TabBar/consumption.imageset/conumption@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..1ad269b64282cd65365f61c92b8a8af716344541 GIT binary patch literal 3774 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 literal 0 HcmV?d00001 diff --git a/caffeine/Assets.xcassets/TabBar/consumption.imageset/conumption@3x.png b/caffeine/Assets.xcassets/TabBar/consumption.imageset/conumption@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..5d705d31e599f30c3afa6815f2d2e8ff2128314e GIT binary patch literal 4303 zcmV;=5HRnFP)002t}1^@s6I8J)%00009a7bBm000XU z000XU0RWnu7ytkYPiaF#P*7-ZbZ>KLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=0000WV@Og>004R=004l4008;_004mL004C`008P>0026e000+nl3&F} z000I0Nkl(I&Q36K!o{V`HLg+oa=%IfHj^W_M?H z-sApZ;LgI{d*(mqo_p@O=S;>h3@UJjstN@avVwtO7zM8YunsVMx~>Y73&SufnpK&G z0iinN@iqY6KK1o$*komj*``b;lP1Nu05}W`7qeM$GVoF1a?!*cKwY^8{{KMM6~Lgf zihc^zR#roM{H@*31GWH@z@0*>Tg;Z#Q0?;#AR8A0 ze+uv@u+zt_jv=;a18}2Dd2W#Zs(r1s+^DF?ss~ofR4Vo0C&Z@g6Q}hDpda|lA#q*6 ztw6>FVaK#SRz*QpwP@0xMIP=uU=6TTmi8${`fCK{1CNM}87k86m%!By8Y;@B%Q&L0^kSlN-afSsew0-wE6v(5Af!c(%Y| z(dF>PWW)5}vtl51VGjZKyRai(&{Tdx;CPPb!Aq9Q9JK2F&xA271Ot2QsPEef)p(gYd8pP2Ydm~r}b zz#^})Ix+sLoJW8eVUo2#)LQkV=lY}(sssC^AHhu<4eKi8R`^ZUX~1vV;EQ~mK7NyB zP05cnnV$=TtXG^28Z)v0&d^rLF*{G+PqJpq9?lxDM~?@^m@H(&t#6GoL6Nmh8|=CO zR4ENi`=nso>HC)Y10{P5y{>}M^sOYFZSoRD>!(*7CvjO62WrG2u* z$2^l&D=veDcSLoQj`t;Gt%jLBlXX3Cl5)S5bl^DfxpLp;2U*u@t6(ST!8WDcf_Vz% ziL4f-y;ppcw4kTRvzA5H#Y(%EbfHhXZ}m!6lhXbvWn}fshT6i}Udd9A$cIu!)(Oq5 zO!bqj5z>d@0?%5uQ>w0pX-3v7SvjR$mqLQnsW2(L^YCs zaBsXvseu;^CWlVz_M=kTnhXMk8!DaBhrjXWor{1?w2_ z7H|^|&gUH9Ow4N8UDy|bb^_~FgyfYtNJNY4G%SSaz)tQ~6G*yEj}xg)IN^?*PzWnj^U!c_jb<002ovPDHLkV1hhC7}Wp( literal 0 HcmV?d00001 diff --git a/caffeine/Assets.xcassets/TabBar/input.imageset/Contents.json b/caffeine/Assets.xcassets/TabBar/input.imageset/Contents.json new file mode 100644 index 0000000..39b026c --- /dev/null +++ b/caffeine/Assets.xcassets/TabBar/input.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "input@1x.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "input@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "input@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/caffeine/Assets.xcassets/TabBar/input.imageset/input@1x.png b/caffeine/Assets.xcassets/TabBar/input.imageset/input@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..96a7bff7d9f9b10dacdca3fe9e415dbda3528e3b GIT binary patch literal 3094 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 literal 0 HcmV?d00001 diff --git a/caffeine/Assets.xcassets/TabBar/input.imageset/input@2x.png b/caffeine/Assets.xcassets/TabBar/input.imageset/input@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..affca10df5bc17dd8c379bff688fd3b70c21171f GIT binary patch literal 3447 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 Z9sp!^I?jpFB{Tp4002ovPDHLkV1nMxS8M

002t}1^@s6I8J)%00009a7bBm000XU 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 LNkvXXu0mjfsSZDE literal 0 HcmV?d00001 diff --git a/caffeine/Assets.xcassets/TabBar/settings.imageset/settings@2x.png b/caffeine/Assets.xcassets/TabBar/settings.imageset/settings@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..b52c3b2e39cc8771467dd114dd7ed78a46f95348 GIT binary patch literal 4156 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 XArW;=CQj%f00000NkvXXu0mjfj94OM literal 0 HcmV?d00001 diff --git a/caffeine/Assets.xcassets/TabBar/statistics.imageset/Contents.json b/caffeine/Assets.xcassets/TabBar/statistics.imageset/Contents.json new file mode 100644 index 0000000..0df2635 --- /dev/null +++ b/caffeine/Assets.xcassets/TabBar/statistics.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "statistics@1x.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "statistics@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "statistics@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/caffeine/Assets.xcassets/TabBar/statistics.imageset/statistics@1x.png b/caffeine/Assets.xcassets/TabBar/statistics.imageset/statistics@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..ee13b1a08d703d3524792664e1147eafb1b38195 GIT binary patch literal 3201 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 literal 0 HcmV?d00001 diff --git a/caffeine/Assets.xcassets/Total/Contents.json b/caffeine/Assets.xcassets/Total/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/caffeine/Assets.xcassets/Total/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/caffeine/Assets.xcassets/Total/totalCupsIcon.imageset/Contents.json b/caffeine/Assets.xcassets/Total/totalCupsIcon.imageset/Contents.json new file mode 100644 index 0000000..a82ace1 --- /dev/null +++ b/caffeine/Assets.xcassets/Total/totalCupsIcon.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "totalCupsIcon.pdf", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/caffeine/Assets.xcassets/Total/totalCupsIcon.imageset/totalCupsIcon.pdf b/caffeine/Assets.xcassets/Total/totalCupsIcon.imageset/totalCupsIcon.pdf new file mode 100644 index 0000000000000000000000000000000000000000..5e88ec339630cc031752c505d2aba5ef07a6e034 GIT binary patch literal 4977 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 G=zjoP7&X=a literal 0 HcmV?d00001 diff --git a/caffeine/Assets.xcassets/Total/totalMilkIcon.imageset/Contents.json b/caffeine/Assets.xcassets/Total/totalMilkIcon.imageset/Contents.json new file mode 100644 index 0000000..111d496 --- /dev/null +++ b/caffeine/Assets.xcassets/Total/totalMilkIcon.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "totalMilkIcon.pdf", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/caffeine/Assets.xcassets/Total/totalMilkIcon.imageset/totalMilkIcon.pdf b/caffeine/Assets.xcassets/Total/totalMilkIcon.imageset/totalMilkIcon.pdf new file mode 100644 index 0000000000000000000000000000000000000000..bb647d39c52b907aafb8948abd727370212d0644 GIT binary patch literal 4330 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 Nx*=e&mVq|#{{T+EYeWD5 literal 0 HcmV?d00001 diff --git a/caffeine/Assets.xcassets/Total/totalSugarIcon.imageset/Contents.json b/caffeine/Assets.xcassets/Total/totalSugarIcon.imageset/Contents.json new file mode 100644 index 0000000..5ca2640 --- /dev/null +++ b/caffeine/Assets.xcassets/Total/totalSugarIcon.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "totalSugarIcon.pdf", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/caffeine/Assets.xcassets/Total/totalSugarIcon.imageset/totalSugarIcon.pdf b/caffeine/Assets.xcassets/Total/totalSugarIcon.imageset/totalSugarIcon.pdf new file mode 100644 index 0000000000000000000000000000000000000000..0effbaed68d8ec7f3275f679f8a849573f9ecec9 GIT binary patch literal 4239 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 Plai1C^Yg1{tAhUnUB^OG literal 0 HcmV?d00001 diff --git a/caffeine/Assets.xcassets/disclosure.imageset/Contents.json b/caffeine/Assets.xcassets/disclosure.imageset/Contents.json new file mode 100644 index 0000000..f692b56 --- /dev/null +++ b/caffeine/Assets.xcassets/disclosure.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "disclosure.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "disclosure@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "disclosure@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/caffeine/Assets.xcassets/disclosure.imageset/disclosure.png b/caffeine/Assets.xcassets/disclosure.imageset/disclosure.png new file mode 100644 index 0000000000000000000000000000000000000000..86189e8eb7bb1ae2beab9e8d56b1f4903a04ac6e GIT binary patch literal 145 zcmeAS@N?(olHy`uVBq!ia0vp^93VCa8<3oGNZ$fTF%}28J29*~C-V}>@%D6a43Usb z{_+3+ekK8VhKoEm7(#?R{?<2y3VH}=aV}x&Rbrozyx;*t*YSp?9kM>ko)efG+~gaq qUND}J5^;AFZIEFLYSH8jVPI&pIDeciMg9ZOSO!m5KbLh*2~7ZC(J12p literal 0 HcmV?d00001 diff --git a/caffeine/Assets.xcassets/disclosure.imageset/disclosure@2x.png b/caffeine/Assets.xcassets/disclosure.imageset/disclosure@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..a8dab61d8b30bff00809d57bcdef36b314606aaf GIT binary patch literal 181 zcmeAS@N?(olHy`uVBq!ia0vp^0zfRq!3HGvW!zy0QjEnx?oJHr&dIz4a`HW0978Mw z-v(XeJ7B<)V!!Y0>E5>Xn@hf|<@8jZb?;#ngOp3j$&I_Fh@Q!G>1|QGbklv-6Am}q znTEbhpKkOoD4kr>n(13-(m6*$qU7PM+3R+1Ik?__c63GX!5iTdh4WqJyw5#W^80zC fn?j`LsR!)sy*k423axTLs~J39{an^LB{Ts5oY_S* literal 0 HcmV?d00001 diff --git a/caffeine/Assets.xcassets/disclosure.imageset/disclosure@3x.png b/caffeine/Assets.xcassets/disclosure.imageset/disclosure@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..c0e8f4bc54d2c809128d410e736238c1e4f7aeef GIT binary patch literal 243 zcmeAS@N?(olHy`uVBq!ia0vp^5I$EH7M{n+jhBsd|}OHeo!w;Ic1i>vH0l|xL#?S?8>bUU0ZtG;QIBVb5D8o1N5)k z2)Ex2I1y~AcEGh@*O}Q3DNAZ!%;8*6ufAZp&pQ9uLf*fhy1WZFwz{m^_G!yhYTbrA#`DfJTyl7T) rvAKe~n&k)n$uSk_Np(u=&c5Qj#I-$2Jjm}R(BTZ8u6{1-oD!MA%MM)ILMM+Lv zD!~aV!5=`8xWIu6Ck`Bdp4*d-YhGnsJdsScz6|j*wt$l$Wjn(JyNU$J zIYR!rBJ)>or&8N&LlqT`2s4}H~-ePSJgHc6REnj=dJ0%2e03txr5r5bBWtxFjt3P}gpt`Yt>pq&$lp zhlquku>NO(Z0sqlEsU^4!m}xb`|(VA>aus<$YUZgwjiW+k$g%CBY4mfMrSBlgM(*Y zh{a>Ku$P`9AgAcOYgzJd$~QW>E*!C2>}m3gk-J&Q7ha#6yZR@dx*V3k!kj)m-qqCw zUt+g>h<($=aoV^#uz@07*xV3bT)#fK5yWpGVTOi=o@2&&mDoda_CKl`b4kKk(6o7RQVildmaX3AVy|bq3_#nz5!(n8g#uu^2`;oPq{FFPg z^?S^|N9QU@IbudeCf>Ge;ja%sz}MTk_0Q+$=Zh+i8eL{!V4$V7z56REiKpBKp(Ko@*Z?U&j(TMs zkl%Xwupg^f%Wd#_w=TMpFp0$YaT>p53CD0@UFNUVwHl%?iItcMiP}JIQNdFZ1`Qwe zjY;_FW-7JrpNBkCVnt>Tv#KrL#TrK?VT3J9(L(hlh`(ys3Hc>Scg}LEXp48L)=_El zm9FT+rGF{m?RjK0IdP|!v9MmlbxaS9BTA*VD1fR7BcT^fmJLhUi5dDtCgD29XT|3z zY|H*hX(-{wQ*3`z(I}zX7A0Y_BL59e>nG`h_a%Rk7Y!+h5^i|>)D{))-566Tjb#$a z@gHzC`H^DrP!z*e`UPB&o(lq_6fuqIVM zILv{C$!105gyAp;7G_~#8aKM3v76nM<05b#9+sJdRSYZ)nFkS_37E^u5(Xc!qcZ_B zSy{s1=1gSf87?bJ7<_b(OvG?mxxz#yVo(?stJ2f;-uc|J3h1o0>hjvXd!mrfS6yrL zNh}^0hx_`f+!l)tE4l+eEA4o-6QdJ3e46*4x|f%3i>+L)3aZg3ZSC#i*zps-Ta1=M zdgcnflH&Lm6*H`eDLaBcaF52PXh$g9VvS5i)cuRaTdSiO7Z%7ETom%e6$YzH3Q=E} z{-e*6y^y66Ba4aO#Snp8wgw|#7!iqEHf!Rg5MvAD%J4rH=rHnyiNL;$tHH2!(R>phChs$u54;+#Vb)5FOiyfKcKop?Hzu!gHSWWs=Rivs{Ea5G z!%3G-OBh^PhBjh!*|dbgSJgusF}iG8!T`9TjTl`vEny0U@Xj&1Y}{=JZ}OIj(eW(4 zP0;3D2*VLy``Aj)Om-j(zO}+jS`kxnEaeK%^#Rr@GqFV>GF@S?PeM2W8(`Adk16*! zzDclzZ$J3m?>LUgHFzg4j$4}a@e(n4dG1kL7)ftG?CMh5-n@IKv7@V}w-@(%kN6st znEW$dMtdmXM5o<5JoLxcGQp%BF^+95SE}35(IH-W^|i-SAHX-(p1o#b(siRPO!nWk zmF`2m_-Imo15hGlY!9d|WRUt8Es%Y5UwbT9c6Jc|e%ZyvMf%NT_dQzwo2F$}cbK#Q zw1pw>IQMFYu2w6mD)WCCs5E0l7&I7~30QX@#uLYgFuHpm9*l{jDHb!r7+6r55QS`* zSlp2vBf?nVhGvd2#bQJl*Ug7!jxohzM3_t_vxduu|0o2Tnedl^O=2;@U_=-K!S!9! zhm)y061B&eFu3{A^xd`w>uGC~@8F-p^qa9*-wOUI-|E&D l{5U^9^-ukhPrfyx!2cRLAc<^VrltS@002ovPDHLkV1h?-CPM%K literal 0 HcmV?d00001 diff --git a/caffeine/Assets.xcassets/launchIcon.imageset/launch@2x.png b/caffeine/Assets.xcassets/launchIcon.imageset/launch@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..16eff6903173af65a4515e9b56202c143090f203 GIT binary patch literal 3327 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 literal 0 HcmV?d00001 diff --git a/caffeine/Assets.xcassets/selectIcon-green.imageset/Contents.json b/caffeine/Assets.xcassets/selectIcon-green.imageset/Contents.json new file mode 100644 index 0000000..dcd1baf --- /dev/null +++ b/caffeine/Assets.xcassets/selectIcon-green.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "selectIcon-green.pdf", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/caffeine/Assets.xcassets/selectIcon-green.imageset/selectIcon-green.pdf b/caffeine/Assets.xcassets/selectIcon-green.imageset/selectIcon-green.pdf new file mode 100644 index 0000000000000000000000000000000000000000..611147598d0be39a9bf10bc4e57e293b0bffc280 GIT binary patch literal 4052 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

-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 literal 0 HcmV?d00001 diff --git a/caffeine/Assets.xcassets/vektor.imageset/vektor@3x.png b/caffeine/Assets.xcassets/vektor.imageset/vektor@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..dc0267771a45dc9caa82f68020f0517eb4808c9f GIT binary patch literal 3358 zcmai1XHXOTll~z{Z_=wTksj&2mxNvgf>fmw5RoEEQw-9JARyf!sPrO&f}t6DlOP~9 z6d@pj0!lGR%kj?5{paq}eb{}r%`>w*`(ZcfnuQ?)Ee|aKfWg>E&-xq_&c&IU@?7g( zF8g*4G=WAAcLAVd{a469!E-JEXf1u=@N3t60zv}r`UC_D7{lQLfx!XZzPG&q2%AIO zAQ3hj9Gb+%eVAz?>X~VPH9NI{H7o_imLUR#&@h`MLP}=YtvWC1>r?O!6ep6WrJ+*U ztt9A^X=kWbAurQnUL__E9WO_|@|$WSej7P^KdrT1vxjaRrNUCv=NQRbDWd2rVV5s` zjp^^{TV9pYiKZ0_1kBWpo{+nzf@I(@N<-u76)aT;APbwIqXt;>LaYp50*Pr8mhVi4 ziY3E_WT==@qu78>L>jCN=opZp(0L*@pqK)<4tuy0z%@zWD*EW#1VEt=^CQWC(=!M= zS#bssVD(DW13v1YX7qZpKCqVoY~H3ls$fPE$Qavs8-e;}fWH2`XQAY+vnCk`kg zf$M;vU>Jza2W$qrb{fC0)-kU`&nK1Npn(xm)sJ?fmJFh@vy-|khBM~8%BJLY!L2|? zsw+I7TP|9G>FeGn0E#o%&%50_4Z|_k;c!Z6O^hy*n;$7jSKQqRXKSO?fjR&zheVB? zNk}*HpwuZ*{%0?Rw<&yX(iPt$rg%3n>AVNU8*_Ghf&b1%zvL-qc6M!bb;hIz=HxbH z_wWqa<$|?4z5O>zu21`BrF^5AG_mgU-_i|Fn(0U<{1aDt zjNLKzP&R@UOHi6#LF%4d>6Ii{rg*RLILUKmN#dAXYe^B*-_jzB%#f_O;X(e#RFv61 z1iL~6V7E1(^NScYIm#zyc{G%?qkU>vEDTWI#+g9?+|(12LJT!(_fwy*U~x3GUYB>j zlS=|i$=7*tzLW06RVfxG)YAoHhS7SW_<~)+sIbe}y#WDC+c ziVHsnzvIzNRVrEkTeRUsC{q-91 z)}#ZE(YK)#EYbQ{8YPNQn1I`5T_bxldy5&P3IRSLg-dfZ$~5G$R$Zc3vMNm9iL_k$ z+r#B9C!1hzBq2D(lFlm49GM93Q5IrJg3F0wo?bA1`x-IMGHx(_$69bhqOwrIh(|DM zaL&`OflBq6guvB-xK;FO_p1CV?1i5Bgy6ZHDfW<|_;=#~lh8uOaM8l_jBoUZMw z0_%l}62v9NbVpciNt5*(tAq+xg?k06BQYGtrlqwnvnP0bIDLq|Z@!1LTw2J!Y?1rf zZhUyd@O$oe^8HYHhIsav{zRl0cOe%Q7m_=a>rI|n8TUjAcRxZ#S@uWXdOlNrfUP~W z3HpFNV~94}BwHk#7b=aYtSYNotfI5svmHjHSKhRFSZ81>Z$qf0`I1v@TZO*%!-m%e zS*c!;P=%}rKxn^?ayU(*bm%tgwuHa7Dt_xiXzLT8^Wbg_lYsa!RL9?oR_qaZJ2Ly= zKD0IOl)p7av#PR06)tZgZ`WwO_smIscx$rUDmGO>Tn#*sM~KM>MUxAOvhbBuiMPpER@rhbC_$Y z9n?ux`IYjPwCaU^yi>lNSJZJ6Rb&=Wz8K!Ve#G}s`V?{Me^h>8NN-QsNH0W*r^j(= z^eP4gXz)w-<9}PhZ*=RxOWm^Fa+hN>Fk>38CJmk#Fs1tTITM5k{(b&^uS6(CAR?yb zo95dE*5;Tp@iKKYb+i7FPa`i!rt%dFHD#ye)(h7Qrwf;wT^++5C7LRlK6n{7tU8uC zY&W&tiE~tSD7CkBywPY-i>?)(YOQT8zf_K~$g-#|nnHHh|85#=s%+-2Uz?%C*ERV! zJ#<65b0V92>$O~wOi40*JS>%~B~{4Vw=mGYY7%k~bYnSU`~Y3p zSlG2yfq%2DwC%f{F#qC{!VB>t2l>07y9eN3t=7i0>0V^Z_$}2$S;8%&k?+?9r9GrG z>}sd$n@dBhh;BQaT7R^HUl6ni8p?}uiw-WIl(EeN&BK=60YxrxOYld6Bu`QVX$+L3 zgvpTPNzuB|P8W_3BOX9LrfI9;z5X=JZt12LV|3Yd(;wG9UhAxd_ze7fS_>hr=ixGN zzKn6#qP|akrgHn{meL(XFB+E+XBV%X7MN(yGbWp>7&f6PyB-LSNmc367vb`+21)nZRdu4BV< z=CVJU5t|QN<4p({`j|ie>|JGb55{xUd)#~D+oEKV6Jt(Q?zddVI}EdP?--V@zuP+a zqmP%)9TCH~#x%h(uRdygX!9x`#EqzHBVHr+5l0B6?eT^8ZqtW%#U&!<=LP8?_exL0kRgq3>o|X={Q60gi10fG1xwN-nSwcs29GvL8MtCUS?36yPq0avrIMd&wYL*zw|9w z!ES*;p-sWDle<%kWlkh`O)=xp@ED5<~m zuK1Ttk?S6~rCUq^J1xv1%j5c_ly&tsb)56=hmhR{{2Hs>2fKndYA*hpA)6X!SreB1 ztM+iJnC*!6_mSSj4c;PU+`@i)_-_u<)MSyW=0f{kL;$guc(BB=5EU$XiW_d7 z4Hez4ZL@51+1J_9orNzXOlmuw&Cl%2Ke~ktE#4cOHzZQV#f+Y19HcYBFQ(_G563ga z|0q(?QdM2i4nEyDDTj}Gj*1jIc@-OPX>TZR{+%V0N@PBbm=t!;DWKSo-QJ6?&qAW zAFCT5>i7D133DJPBNZf1 zFHt?>cm1yAQ5M{tmNd4k&!8+ELGLp!DNZocd z*sP;&s2p3)LAAYvZM+lktJm@>3A6w7kE3(2bhAt_N$i+5?|nT^qBbt52DcGJnd)eN z>)DiC8haxX-vZ$@eVoSuDwiJ90#!zhVja7iJAhJad#7<-WbWzo`o^;P_VQHL^KR-( zh7A+H0@X~3Ju25p`-ijVwh2*zF=0Xl?o$!{Zh2YZ7^1K_IMx%Wmc(N4LFFt+g+Vqp zK24Az(`=!L{V#plfz(tX~f~x;HL<-uXl6@@mU!<{z%| z1kH}#QbM9zY?@$r_pVC-y39`|Ev&p>+BI@e7{9?opx$)t3{*3JL|0w^1k>$11No9g z813FriQwv!eWb#m8GGyZ$6U7?+3?Vnq4O;RBoaCJb9}F+BsKK>eF4B&-$Jhr=KA=* E0DF5%5dZ)H literal 0 HcmV?d00001 diff --git a/caffeine/Base.lproj/LaunchScreen.storyboard b/caffeine/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..a690a55 --- /dev/null +++ b/caffeine/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/caffeine/Base.lproj/Main.storyboard b/caffeine/Base.lproj/Main.storyboard new file mode 100644 index 0000000..9f96e85 --- /dev/null +++ b/caffeine/Base.lproj/Main.storyboard @@ -0,0 +1,3981 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/caffeine/Data/Consumable.swift b/caffeine/Data/Consumable.swift new file mode 100644 index 0000000..8ffea0b --- /dev/null +++ b/caffeine/Data/Consumable.swift @@ -0,0 +1,137 @@ +import Foundation + +struct Consumable: Codable, Equatable { + let coffee: Coffee + let milk: Milk + let size: Size + let sugar: Sugar + let date: Date + + static let defaultRecentDrinks: [Consumable] = [ + .init( + coffee: .doubleShot, + milk: .fullFat, + size: .small, + sugar: .twoPieces, + date: .init() + ), .init( + coffee: .singleShot, + milk: .soyMilk, + size: .medium, + sugar:. singlePiece, + date: .init() + ), .init( + coffee: .tripleShot, + milk: .lactoseFree, + size: .large, + sugar: .noSugar, + date: .init() + ) + ] +} + +enum Coffee: Int, Codable { + case noShot + case singleShot + case doubleShot + case tripleShot + + var localizedTitle: String { + switch(self) { + case .noShot: + return NSLocalizedString("noshot", comment: "") + case .singleShot: + return NSLocalizedString("singleshot", comment: "") + case .doubleShot: + return NSLocalizedString("doubleshot", comment: "") + case .tripleShot: + return NSLocalizedString("tripleshot", comment: "") + } + } +} + +enum Milk: Int, Codable { + case black + case lactoseFree + case fullFat + case soyMilk + + var localizedTitle: String { + switch(self) { + case .black: + return NSLocalizedString("black", comment: "") + case .lactoseFree: + return NSLocalizedString("lactosefree", comment: "") + case .fullFat: + return NSLocalizedString("fullfat", comment: "") + case .soyMilk: + return NSLocalizedString("soymilk", comment: "") + } + } +} + +enum Size: Int, Codable { + case noSize + case small + case medium + case large + + var localizedTitle: String { + switch(self) { + case .noSize: + return NSLocalizedString("nosize", comment: "") + case .small: + return NSLocalizedString("small", comment: "") + case .medium: + return NSLocalizedString("medium", comment: "") + case .large: + return NSLocalizedString("large", comment: "") + } + } + + var imageName: String { + switch(self) { + case .noSize: + return "quickShot" + case .small: + return "quickSmall" + case .medium: + return "quickMedium" + case .large: + return "quickLarge" + } + } + + var imageNameSelected: String { + switch(self) { + case .noSize: + return "quickShotPressed" + case .small: + return "quickSmallPressed" + case .medium: + return "quickMediumPressed" + case .large: + return "quickLargePressed" + } + } +} + +enum Sugar: Int, Codable { + case noSugar + case singlePiece + case twoPieces + case threePieces + + var localizedTitle: String { + switch(self) { + case .noSugar: + return NSLocalizedString("nosugar", comment: "") + case .singlePiece: + return NSLocalizedString("singlepiece", comment: "") + case .twoPieces: + return NSLocalizedString("twopiece", comment: "") + case .threePieces: + return NSLocalizedString("threepiece", comment: "") + } + } +} diff --git a/caffeine/Data/ConsumableProperties.swift b/caffeine/Data/ConsumableProperties.swift new file mode 100644 index 0000000..4ce811a --- /dev/null +++ b/caffeine/Data/ConsumableProperties.swift @@ -0,0 +1,149 @@ +import Foundation + +/* +* +* A consumption object represents a Drink which can be consumed +* The Nutrition Data is loaded from essential .plist Files +* Call calculateHKValuesForSetup(coffee: Coffee, milk: Milk, size: Size, sugar: Sugar) +* to setup the Object with all Nutritionfacts +*/ +struct ConsumableProperties { + + let title = NSLocalizedString("ConsumptionTitle", comment: "Caffeine Companion") + + private(set) var volume: Double = 0.0 + private(set) var caffeine: Double = 0.0 + private(set) var energyCalories: Double = 0.0 + private(set) var fat: Double = 0.0 + private(set) var saturatedFat: Double = 0.0 + private(set) var unsaturatedFat: Double = 0.0 + private(set) var sodium: Double = 0.0 + private(set) var potassium: Double = 0.0 + private(set) var carbs: Double = 0.0 + private(set) var sugar: Double = 0.0 + private(set) var protein: Double = 0.0 + private(set) var amountOfMilk: Double = 0.0 + + init(_ consumable: Consumable) { + loadDataForCoffee(consumable.coffee) + loadDataForMilk(consumable.milk, size: consumable.size) + loadDataForSugar(consumable.sugar) + } + + // MARK: Loading From plist Files + + /* + * + * Loads nutrition Data for Coffee depending on the + * kind of coffee + * + */ + private mutating func loadDataForCoffee(_ coffee: Coffee) { + let path = Bundle.main.path(forResource: "Coffee", ofType: "plist") + let coffeeArray = NSArray(contentsOfFile: path!) + var data: Dictionary + let modifier: Double = 1.0 + + switch(coffee) { + case .noShot: + data = coffeeArray?.object(at: 0) as! Dictionary + case .singleShot: + data = (coffeeArray?.object(at: 1))! as! Dictionary + case .doubleShot: + data = coffeeArray?.object(at: 2) as! Dictionary + case .tripleShot: + data = coffeeArray?.object(at: 3) as! Dictionary + } + loadNutritionDataWithModifier(data, modifier: modifier) + } + + /* + * + * Loads nutrition Data for Milk depending on the + * kind of milk and the size of the mug into the vars + * + */ + private mutating func loadDataForMilk(_ milk: Milk, size: Size) { + let path = Bundle.main.path(forResource: "Milk", ofType: "plist") + let milkArray = NSArray(contentsOfFile: path!) + var data: Dictionary = Dictionary() + + switch(milk) { + case .black: + data = milkArray?.object(at: 0) as! Dictionary + case .lactoseFree: + data = milkArray?.object(at: 1) as! Dictionary + case .fullFat: + data = milkArray?.object(at: 2) as! Dictionary + case .soyMilk: + data = milkArray?.object(at: 3) as! Dictionary + } + + let sizePath = Bundle.main.path(forResource: "Size", ofType: "plist") + let sizeArray = NSArray(contentsOfFile: sizePath!) + var sizeDict: Dictionary = Dictionary() + var modifier: Double = 1.0 + + switch(size) { + case .noSize: + sizeDict = sizeArray?.object(at: 0) as! Dictionary + case .small: + sizeDict = sizeArray?.object(at: 1) as! Dictionary + case .medium: + sizeDict = sizeArray?.object(at: 2) as! Dictionary + case .large: + sizeDict = sizeArray?.object(at: 3) as! Dictionary + } + modifier = (sizeDict["volume"] as! Double - volume) / 100 + amountOfMilk = data["volume"] as! Double * modifier + loadNutritionDataWithModifier(data, modifier: modifier) + } + + /* + * + * Loads nutrition Data for Sugar depending on the + * selected number into the vars + * + */ + private mutating func loadDataForSugar(_ sugar: Sugar) { + let path = Bundle.main.path(forResource: "Sugar", ofType: "plist") + let sugarArray = NSArray(contentsOfFile: path!) + var data: Dictionary = Dictionary() + let modifier: Double = 1.0 + + switch(sugar) { + case .noSugar: + data = sugarArray?.object(at: 0) as! Dictionary + case .singlePiece: + data = sugarArray?.object(at: 1) as! Dictionary + case .twoPieces: + data = sugarArray?.object(at: 2) as! Dictionary + case .threePieces: + data = sugarArray?.object(at: 3) as! Dictionary + } + loadNutritionDataWithModifier(data, modifier: modifier) + } + + /* + * + * Outsourcing of the Interpretation for all Load-Functions + * modifies the class Variables with Data and Modifier + * + */ + private mutating func loadNutritionDataWithModifier( + _ data: Dictionary, + modifier: Double + ) { + volume = volume + (data["volume"] as! Double) * modifier + caffeine = caffeine + (data["hkcaffeine"] as! Double) * modifier + energyCalories = energyCalories + (data["hkenergyCalories"] as! Double) * modifier + fat = fat + (data["hkfat"] as! Double) * modifier + saturatedFat = saturatedFat + (data["hksaturatedFat"] as! Double) * modifier + unsaturatedFat = unsaturatedFat + (data["hkunsaturatedFat"] as! Double) * modifier + sodium = sodium + (data["hksodium"] as! Double) * modifier + potassium = potassium + (data["hkpotassium"] as! Double) * modifier + carbs = carbs + (data["hkcarbs"] as! Double) * modifier + sugar = sugar + (data["hksugar"] as! Double) * modifier + protein = protein + (data["hkprotein"] as! Double) * modifier + } +} diff --git a/caffeine/Data/PeriodicConsumption.swift b/caffeine/Data/PeriodicConsumption.swift new file mode 100644 index 0000000..6a0e4e3 --- /dev/null +++ b/caffeine/Data/PeriodicConsumption.swift @@ -0,0 +1,110 @@ +import Foundation + +enum Period { + case day + case week + case month + case year + + init(with selectorState: SelectorState) { + switch selectorState { + case .day: + self = .day + case .week: + self = .week + case .month: + self = .month + case .year: + self = .year + } + } + + var iterations: Int { + switch self { + case .day: + return 24 + case .week: + return 7 + case .month: + return 31 + case .year: + return 365 + } + } + + var inSeconds: Double { + let minute = 60.0 + let hour = minute * 60.0 + + switch self { + case .day: + return hour * Double(self.iterations) + case .week: + return Period.day.inSeconds * Double(self.iterations) + case .month: + return Period.day.inSeconds * Double(self.iterations) + case .year: + return Period.day.inSeconds * Double(self.iterations) + } + } +} + +struct PeriodicConsumption { + let period: Period + + private let rawData: [Consumable] + + private var rawDataProperties: [ConsumableProperties] { + return rawData.map { ConsumableProperties($0) } + } + + var periodicData: [[Consumable]] { + var periodicData: [[Consumable]] = .init(repeating: [], count: period.iterations) + + switch period { + case .day: + rawData.forEach { + let hour = Calendar.current.component(.hour, from: $0.date) + periodicData[hour].append($0) + } + case .week: + rawData.forEach { + let weekday = Calendar.current.component(.weekday, from: $0.date) + periodicData[weekday - 1].append($0) + } + case .month: + rawData.forEach { + let day = Calendar.current.ordinality(of: .day, in: .month, for: $0.date) ?? 0 + periodicData[day - 1].append($0) + } + case .year: + rawData.forEach { + let month = Calendar.current.ordinality(of: .day, in: .year, for: $0.date) ?? 0 + periodicData[month - 1].append($0) + } + } + + return periodicData + } + + var shots: Int { + return rawData.reduce(0, { $0 + $1.coffee.rawValue }) + } + + var caffeine: Double { + return rawDataProperties.reduce(0.0, { $0 + Double($1.caffeine) }) + } + + var milk: Double { + return rawDataProperties.reduce(0.0, { $0 + Double($1.amountOfMilk) }) + } + + var sugar: Double { + rawDataProperties.reduce(0.0, { $0 + Double($1.sugar) }) + } + + init(_ period: Period, _ consumables: [Consumable]) { + self.period = period + self.rawData = consumables + } +} diff --git a/caffeine/Data/UserSettings.swift b/caffeine/Data/UserSettings.swift new file mode 100644 index 0000000..916ff0c --- /dev/null +++ b/caffeine/Data/UserSettings.swift @@ -0,0 +1,129 @@ +import Foundation + +let defaults = UserDefaults(suiteName: "caffeine") + +@propertyWrapper +struct UserDefault { + let key: String + + init(_ key: String) { + self.key = key + } + + var wrappedValue: T? { + get { + return defaults?.object(forKey: key) as? T + } + set { + defaults?.set(newValue, forKey: key) + } + } +} + +/// The Settings object can be used to easily access the standard +/// UserDefaults. This way we can ensure that identifier are stored +/// in a centralised way. +struct UserSettings { + + // swiftlint:disable let_var_whitespace + @UserDefault("caffeine.age") + private static var age: Int? + + @UserDefault("caffeine.weight") + private static var weight: Int? + + @UserDefault("caffeine.height") + private static var height: Int? + + @UserDefault("caffeine.sensibility") + private static var sensibility: Int? + + @UserDefault("caffeine.sex") + private static var sex: Int? + + @UserDefault("caffeine.sex") + private static var steroids: Bool? + // swiftlint:enable let_var_whitespace + + static var userAge: Int { + get { + guard let age = UserSettings.age else { + UserSettings.age = 18 + return 18 + } + return age + } + set { + UserSettings.age = newValue + } + } + + static var userWeight: Int { + get { + guard let weight = UserSettings.weight else { + UserSettings.weight = 100 + return 100 + } + return weight + } + set { + UserSettings.weight = newValue + } + } + + static var userHeight: Int { + get { + guard let height = UserSettings.height else { + UserSettings.height = 100 + return 100 + } + return height + } + set { + UserSettings.height = newValue + } + } + + static var userSensibility: Int { + get { + guard let sensibility = UserSettings.sensibility else { + UserSettings.sensibility = 50 + return 50 + } + return sensibility + } + set { + UserSettings.sensibility = newValue + } + } + + static var userSex: Int { + get { + guard let sex = UserSettings.sex else { + UserSettings.sex = 50 + return 50 + } + return sex + } + set { + UserSettings.sex = newValue + } + } + + static var userSteroids: Bool { + get { + guard let steroids = UserSettings.steroids else { + UserSettings.steroids = false + return false + } + return steroids + } + set { + UserSettings.steroids = newValue + } + } + + static var userBmi: Double { + return Double(userWeight) / pow(Double(userHeight), 2) + } +} diff --git a/caffeine/Info.plist b/caffeine/Info.plist new file mode 100644 index 0000000..76c696e --- /dev/null +++ b/caffeine/Info.plist @@ -0,0 +1,39 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleDisplayName + caffe:ne + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.1.0 + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSHealthShareUsageDescription + Caffe:ne needs to share Data with Healthkit to work properly. + NSHealthUpdateUsageDescription + Caffe:ne needs to access Data from Healthkit to work properly. + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + healthkit + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + + + diff --git a/caffeine/Services/ConsumptionStore/Consumption.xcdatamodeld/Consumption.xcdatamodel/contents b/caffeine/Services/ConsumptionStore/Consumption.xcdatamodeld/Consumption.xcdatamodel/contents new file mode 100644 index 0000000..2df7b43 --- /dev/null +++ b/caffeine/Services/ConsumptionStore/Consumption.xcdatamodeld/Consumption.xcdatamodel/contents @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/caffeine/Services/ConsumptionStore/ConsumptionDataProvider.swift b/caffeine/Services/ConsumptionStore/ConsumptionDataProvider.swift new file mode 100644 index 0000000..b41d1ee --- /dev/null +++ b/caffeine/Services/ConsumptionStore/ConsumptionDataProvider.swift @@ -0,0 +1,14 @@ +import Foundation + +/// A class conforming to this protocol provides stored lexicon data. +protocol ConsumptionDataProvider: class { + + func add(consumable: Consumable) + + func getRecentEntries() -> [Consumable] + + func getEntries(for period: Period) -> [Consumable] + + func clear() throws + +} diff --git a/caffeine/Services/ConsumptionStore/ConsumptionStore.swift b/caffeine/Services/ConsumptionStore/ConsumptionStore.swift new file mode 100644 index 0000000..88740a3 --- /dev/null +++ b/caffeine/Services/ConsumptionStore/ConsumptionStore.swift @@ -0,0 +1,187 @@ +import Foundation +import CoreData + +/// A data store for lexicon entries. This can be used to locally persist any type of entries. +/// The `ConsumptionStore` follows the singleton pattern and should be accessed +/// via the .shared property. +final class ConsumptionStore: NSObject { + + /// A static singleton reference. + public static var shared: ConsumptionStore = .init() + + /// The context in which we are manipulating the local database + private var mainContextInstance: NSManagedObjectContext + + /// Private initialiser to enforce the singleton pattern. + private override init() { + mainContextInstance = PersistenceService.shared.getMainContextInstance() + } +} + +// MARK: - Sessions + +extension ConsumptionStore: ConsumptionDataProvider { + + func add(consumable: Consumable) { + let minionManagedObjectContextWorker: NSManagedObjectContext = NSManagedObjectContext( + concurrencyType: .privateQueueConcurrencyType + ) + minionManagedObjectContextWorker.parent = mainContextInstance + minionManagedObjectContextWorker.mergePolicy = NSMergeByPropertyStoreTrumpMergePolicy + + minionManagedObjectContextWorker.performAndWait { + let newEntry = Consumption(context: minionManagedObjectContextWorker) + + newEntry.date = consumable.date + newEntry.coffee = .init(consumable.coffee.rawValue) + newEntry.milk = .init(consumable.milk.rawValue) + newEntry.size = .init(consumable.size.rawValue) + newEntry.sugar = .init(consumable.sugar.rawValue) + + PersistenceService.shared.saveWorkerContext(minionManagedObjectContextWorker) + PersistenceService.shared.mergeWithMainContext() + } + } + + func getRecentEntries() -> [Consumable] { + let fetchRequest: NSFetchRequest = Consumption.fetchRequest() + fetchRequest.fetchLimit = 3 + fetchRequest.sortDescriptors = [.init(key: "date", ascending: false)] + + guard let entries = try? mainContextInstance.fetch(fetchRequest) + .sorted(by: { $0.date ?? .init() < $1.date ?? .init() }) + else { + return [] + } + + return entries.compactMap { + guard + let coffee = Coffee(rawValue: Int($0.coffee)), + let milk = Milk(rawValue: Int($0.milk)), + let size = Size(rawValue: Int($0.size)), + let sugar = Sugar(rawValue: Int($0.sugar)), + let date = $0.date + else { + return nil + } + return Consumable( + coffee: coffee, + milk: milk, + size: size, + sugar: sugar, + date: date + ) + }.reversed() + } + + func getEntries(for period: Period) -> [Consumable] { + let fetchRequest: NSFetchRequest = Consumption.fetchRequest() + fetchRequest.sortDescriptors = [.init(key: "date", ascending: true)] + + switch period { + case .day: + let startOfDay = Calendar.current.startOfDay(for: .init()) + let endOfDay = startOfDay.addingTimeInterval(Period.day.inSeconds) + fetchRequest.predicate = NSPredicate( + format: "date >= %@ && date <= %@", + startOfDay as NSDate, + endOfDay as NSDate + ) + + break + case .week: + guard let startOfWeek = Calendar.current.date( + from: Calendar.current.dateComponents( + [.yearForWeekOfYear, .weekOfYear], + from: .init() + ) + ) else { return [] } + let endOfWeek = startOfWeek.addingTimeInterval(Period.week.inSeconds) + fetchRequest.predicate = NSPredicate( + format: "date >= %@ && date <= %@", + startOfWeek as NSDate, + endOfWeek as NSDate + ) + + break + case .month: + guard let startOfMonth = Calendar.current.date( + from: Calendar.current.dateComponents( + [.year, .month], + from: .init() + ) + ) else { return [] } + let endOfMonth = startOfMonth.addingTimeInterval(Period.month.inSeconds) + fetchRequest.predicate = NSPredicate( + format: "date >= %@ && date <= %@", + startOfMonth as NSDate, + endOfMonth as NSDate + ) + + break + case .year: + guard let startOfYear = Calendar.current.date( + from: Calendar.current.dateComponents( + [.year], + from: .init() + ) + ) else { return [] } + let endOfYear = startOfYear.addingTimeInterval(Period.year.inSeconds) + fetchRequest.predicate = NSPredicate( + format: "date >= %@ && date <= %@", + startOfYear as NSDate, + endOfYear as NSDate + ) + + break + } + + guard let entries = try? mainContextInstance.fetch(fetchRequest) else { + return [] + } + + return entries.compactMap { + guard + let coffee = Coffee(rawValue: Int($0.coffee)), + let milk = Milk(rawValue: Int($0.milk)), + let size = Size(rawValue: Int($0.size)), + let sugar = Sugar(rawValue: Int($0.sugar)), + let date = $0.date + else { + return nil + } + return Consumable( + coffee: coffee, + milk: milk, + size: size, + sugar: sugar, + date: date + ) + } + } + + func clear() throws { + var throwingError: Error? + + let minionManagedObjectContextWorker: NSManagedObjectContext = NSManagedObjectContext( + concurrencyType: .privateQueueConcurrencyType + ) + minionManagedObjectContextWorker.parent = mainContextInstance + minionManagedObjectContextWorker.mergePolicy = NSMergeByPropertyStoreTrumpMergePolicy + + minionManagedObjectContextWorker.performAndWait { + let batchDeleteion = NSBatchDeleteRequest(fetchRequest: Consumption.fetchRequest()) + do { + try minionManagedObjectContextWorker.execute(batchDeleteion) + } catch { + throwingError = error + } + PersistenceService.shared.saveWorkerContext(minionManagedObjectContextWorker) + PersistenceService.shared.mergeWithMainContext() + } + + if let error = throwingError { + throw error + } + } +} diff --git a/caffeine/Services/ConsumptionStore/ContextProvider.swift b/caffeine/Services/ConsumptionStore/ContextProvider.swift new file mode 100644 index 0000000..19bb8b4 --- /dev/null +++ b/caffeine/Services/ConsumptionStore/ContextProvider.swift @@ -0,0 +1,65 @@ +import Foundation +import CoreData +// import LogService + +/// Provides Managed object context's to interact with the database provided by Core Data. +final class ContextProvider: NSObject { + + let datastoreProvider: DatastoreProvider? + + init(with datastoreProvider: DatastoreProvider) { + self.datastoreProvider = datastoreProvider + super.init() + } + + /// A master context reference, with PrivateQueueConcurrency Type. + lazy var masterManagedObjectContextInstance: NSManagedObjectContext = { + var masterManagedObjectContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType) + masterManagedObjectContext.persistentStoreCoordinator = datastoreProvider?.persistentStoreCoordinator + masterManagedObjectContext.mergePolicy = NSMergeByPropertyStoreTrumpMergePolicy + return masterManagedObjectContext + }() + + /// A main context reference, with MainQueueuConcurrency Type. + lazy var mainManagedObjectContextInstance: NSManagedObjectContext = { + var mainManagedObjectContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType) + mainManagedObjectContext.persistentStoreCoordinator = datastoreProvider?.persistentStoreCoordinator + mainManagedObjectContext.mergePolicy = NSMergeByPropertyStoreTrumpMergePolicy + return mainManagedObjectContext + }() + + // MARK: - Core Data Saving support + + /// Saves changes from the Main Context to the Master Managed Object Context. + func saveContext() { + defer { + do { + try masterManagedObjectContextInstance.save() + } catch let masterMocSaveError as NSError { + // LogService.print("Master Managed Object Context save error: \(masterMocSaveError.localizedDescription)") + } catch { + // LogService.print("Master Managed Object Context save error.") + } + } + + if mainManagedObjectContextInstance.hasChanges { + mergeChangesFromMainContext() + } + } + + /// Merge Changes on the Main Context to the Master Context. + private func mergeChangesFromMainContext() { + DispatchQueue.main.async( + execute: { + do { + try self.mainManagedObjectContextInstance.save() + } catch let mocSaveError as NSError { + // LogService.print("Master Managed Object Context error: \(mocSaveError.localizedDescription)") + } catch { + // LogService.print("Master Managed Object Context error.") + } + } + ) + } + +} diff --git a/caffeine/Services/ConsumptionStore/DatastoreProvider.swift b/caffeine/Services/ConsumptionStore/DatastoreProvider.swift new file mode 100644 index 0000000..18935b3 --- /dev/null +++ b/caffeine/Services/ConsumptionStore/DatastoreProvider.swift @@ -0,0 +1,47 @@ +import Foundation +import CoreData + +/// Holds the data store, which is stored in the document's directory of the application. +final class DatastoreProvider: NSObject { + + private let objectModelName = "Consumption" + private let objectModelExtension = "momd" + private let dbFilename = "Consumption.sqlite" + + // MARK: - Core Data stack + + lazy var applicationDocumentsDirectory: URL = { + let urls = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask) + + return urls[urls.count - 1] + }() + + lazy var managedObjectModel: NSManagedObjectModel = { + let bundle = Bundle(for: type(of: self)) + // swiftlint:disable force_unwrapping + let modelURL = bundle.url( + forResource: objectModelName, + withExtension: objectModelExtension + )! + return NSManagedObjectModel(contentsOf: modelURL)! + // swiftlint:enable force_unwrapping + }() + + lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator? = { + let coordinator = NSPersistentStoreCoordinator(managedObjectModel: managedObjectModel) + let url = applicationDocumentsDirectory.appendingPathComponent(dbFilename) + + do { + try coordinator.addPersistentStore( + ofType: NSSQLiteStoreType, + configurationName: nil, + at: url, + options: nil + ) + } catch { + abort() + } + + return coordinator + }() +} diff --git a/caffeine/Services/ConsumptionStore/PersistenceService.swift b/caffeine/Services/ConsumptionStore/PersistenceService.swift new file mode 100644 index 0000000..9fb850a --- /dev/null +++ b/caffeine/Services/ConsumptionStore/PersistenceService.swift @@ -0,0 +1,61 @@ +import Foundation +import UIKit +import CoreData +// import LogService + +/// A service class that supports the storage and merge process of multiple managed object contexts. +final class PersistenceService: NSObject { + + private var mainContextInstance: NSManagedObjectContext + + static var shared: PersistenceService = .init() + + private override init() { + mainContextInstance = (UIApplication.shared.delegate as? AppDelegate)! + .contextProvider.mainManagedObjectContextInstance + super.init() + } + + /// Get a reference to the Main Context Instance + /// + /// - Returns: Main NSmanagedObjectContext + func getMainContextInstance() -> NSManagedObjectContext { + return mainContextInstance + } + + /// Save the current work/changes done on the worker contexts (the minion workers). + /// + /// - Parameter workerContext: NSManagedObjectContext The Minion worker Context that has to be saved. + func saveWorkerContext(_ workerContext: NSManagedObjectContext) { + //Persist new Event to datastore (via Managed Object Context Layer). + do { + if workerContext.hasChanges { + try workerContext.save() + } + } catch let saveError as NSError { + // LogService.dump(saveError) + + // TODO: Not cool either. + Swift.assertionFailure(saveError.localizedDescription) + } catch { + // LogService.dump(error) + } + } + + /// Save and merge the current work/changes done on the minion workers with Main context. + func mergeWithMainContext() { + do { + if mainContextInstance.hasChanges { + try mainContextInstance.save() + } + } catch let saveError as NSError { + // LogService.dump(saveError) + + // TODO: clear the core data model and download again. + Swift.fatalError() + } catch { + // LogService.dump(error) + } + } + +} diff --git a/caffeine/Services/DrinksDataService.swift b/caffeine/Services/DrinksDataService.swift new file mode 100644 index 0000000..abdd64d --- /dev/null +++ b/caffeine/Services/DrinksDataService.swift @@ -0,0 +1,34 @@ +import Foundation + +class DrinksService { + static var sharedInstance: DrinksService = .init() + + private var recentDrinksURL: URL? { + guard let documentDirectoryUrl = FileManager.default.urls( + for: .documentDirectory, + in: .userDomainMask + ).first else { return nil } + return documentDirectoryUrl.appendingPathComponent("recent_drinks.json") + } + + func drink(_ consumable: Consumable) { + ConsumptionStore.shared.add(consumable: consumable) + HealthStoreService.shared.storeConsumedObjectIntoHealth( + .init(consumable) + ) + } + + internal func getRecentDrinks() -> [Consumable] { + var recent = ConsumptionStore.shared.getRecentEntries() + + // If there are too few recent drinks we can take them from + // the default recent drinks in the consumable object + for index in 0.. [Consumable] { + var recent = ConsumptionStore.shared.getRecentEntries() + + // If there are too few recent drinks we can take them from + // the default recent drinks in the consumable object + for index in 0.. PeriodicConsumption { + let entries = ConsumptionStore.shared.getEntries(for: period) + return .init(period, entries) + } +} diff --git a/caffeine/Services/HealthKit/CaffeineDataService.swift b/caffeine/Services/HealthKit/CaffeineDataService.swift new file mode 100644 index 0000000..8552e41 --- /dev/null +++ b/caffeine/Services/HealthKit/CaffeineDataService.swift @@ -0,0 +1,187 @@ +import Foundation +import HealthKit + +class CaffeineDataService { + static var shared: CaffeineDataService = .init() + + // Value for Gender Manipulation [3000 .. 3600] + // Women have an up to 1h longer half-life time of caffeine in blood (3000sec. + 600sec) + private let genderModifier: Double = 3000.0 + private let sensibilityGenderModifier: Double = 600.0 + // Value for Contraceptive Steroids Manipulation [5800 .. 7200] + private let steroidsModifier: Double = 5800.0 + private let sensibilitySteroidsModifier: Double = 1400.0 + // SafeLimits + private let safeLimitAdult = 350.0 + private let safeLimitModifierAdult = 100.0 + + private init() { } + + /* + * + * Uses Age and Weight to calculate the Healthy Ammount of Caffeine + * Returns the Caffeine Value in the Completion Block + * Does not include Body Data yet. + * + */ + func healthyAmount() -> Double? { + HealthStoreService.shared.refreshAge() + + let expectedSensibility = Double(UserSettings.userSensibility) / 100.0 + var safeLimit = 0.0 + var calculationAge: Int { + if UserSettings.userAge >= 0 { + return UserSettings.userAge + } else { + return 18 + } + } + + if calculationAge <= 18 { + safeLimit = (pow(M_E, 0.3222 * Double(calculationAge)) + 21.6243) + safeLimit += (1.0 - expectedSensibility) * (pow(M_E, 0.2521 * Double(calculationAge)) + 9.3297) + } else { + safeLimit = safeLimitAdult + safeLimitModifierAdult * (1.0 - expectedSensibility) + } + + return safeLimit + } + + func getCaffeineConsumption( + in period: Period = .day, + completion: @escaping (Bool, Double?) -> Void + ) { + var caffeine: Double = 0.0 + HealthStoreService.shared.loadConsumedData(for: period) { (success, data) in + guard success else { + return completion(false, nil) + } + + let caffeineUnit: HKUnit = .gramUnit(with: .milli) + + for quantitySample in data { + guard + let quantity: HKQuantity = (quantitySample as? HKQuantitySample)?.quantity + else { + continue + } + caffeine += quantity.doubleValue(for: caffeineUnit) + } + completion(true, caffeine) + } + } + + /* + * + * The Half Life of Caffeine in healthy adults is about 5.7 hours + * Source[1]: http://www.ncbi.nlm.nih.gov/pubmed/7361718?dopt=Abstract + * See default Value + * + * "However, at higher doses (e.g. 250–500mg single dose), the clearance of caffeine is + * significantly reduced and its elimination half-life is prolonged, indicating non-linearity" + * Source[2]: http://www.militaryenergygum.com/wp-content/uploads/Multiple-Dose-Pharmacokinetics.pdf + * See Switch-Case + * + * "The t1/2 (beta) was significantly prolonged in women on OCS (10.7 +/- 3.0 hr vs. 6.2 +/- 1.6)" + * Source[3]: http://www.ncbi.nlm.nih.gov/pubmed/7359014 + * See contraceptiveSteroidsTimeModifier + * + * Concentration is unrelated to weight and healthy situation + * + * This is where most of the Magic happens. Sparkle! + * + */ + func getCaffeineConcentration( + _ completion: @escaping (Bool, Double?) -> Void + ) { + // TODO: Migrate to coredata based information + HealthStoreService.shared.loadConsumedData(for: .day) { [weak self] (success, data) in + guard success else { + return completion(false, nil) + } + + guard + let genderModifier = self?.genderModifier, + let sensibilityGenderModifier = self?.sensibilityGenderModifier, + let steroidsModifier = self?.steroidsModifier, + let sensibilitySteroidsModifier = self?.sensibilitySteroidsModifier + else { + return + } + + var caffeine: Double = 0.0 + let caffeineUnit: HKUnit = HKUnit.gramUnit(with: .milli) + + for quantitySample: HKSample in data { + let quantity: HKQuantity = (quantitySample as! HKQuantitySample).quantity + let caffeineInQuantity: Double = quantity.doubleValue(for: caffeineUnit) + var halfLifeSeconds: Double = 0.0 + + // Linear Interpolation of non Linear Values from [2] + // and average divergence for simplification by Sensibility from [2] + halfLifeSeconds = (0.0224 * caffeineInQuantity + 4.4) * 3600 + let isSensible: Bool = UserSettings.userSensibility > 50 ? true : false + var sensibility: Double = 0.0 + var sensibilityByValue: Double = 0.0 + + if (isSensible) { + sensibility = (Double(UserSettings.userSensibility) - 50.0) / 100.0 + sensibilityByValue = (0.0019 * caffeineInQuantity + 2.63) * + (1.0 - sensibility) + } else { + sensibility = Double(UserSettings.userSensibility) / 100.0 + sensibilityByValue = (-0.0019 * caffeineInQuantity - 2.63) * + (1.0 - sensibility) + } + + halfLifeSeconds = halfLifeSeconds + sensibilityByValue + sensibility = Double(UserSettings.userSensibility) / 100.0 + + let expectedGenderValue: Double = Double(UserSettings.userSex) / 100.0 + let genderTimeModifier: Double = genderModifier + + (sensibilityGenderModifier * (1.0 - sensibility)) + let genderModifier: Double = genderTimeModifier * + expectedGenderValue + halfLifeSeconds += genderModifier + + let contraceptiveSteroids: Bool = UserSettings.userSteroids + let contraceptiveSteroidsTimeModifier: Double = steroidsModifier + (sensibilitySteroidsModifier * + (1.0 - sensibility)) + if contraceptiveSteroids { + halfLifeSeconds += contraceptiveSteroidsTimeModifier + } + + let elapsedTime = Date().timeIntervalSince(quantitySample.startDate) + let caffeineConcentrationOfSample = quantity.doubleValue(for: caffeineUnit) * + pow(0.5, (elapsedTime / halfLifeSeconds)) + caffeine = caffeine + caffeineConcentrationOfSample + } + + completion(true, caffeine) + } + } + +} + +extension CaffeineDataService { + + /// Data for a longer period (e.g. week, month, year) is historically passed as an array of arrays. + /// This function is a wrapper for `calculateCaffeineData` which maps the data onto + /// An array of double. + private func calculateCaffeinePeriodData(_ data: [[HKSample]?]) -> [Double] { + return data.map { + guard let data = $0 else { return 0.0 } + return CaffeineDataService.calculateCaffeineData(data) + } + } + + private static func calculateCaffeineData(_ data: [HKSample]) -> Double { + return data + .compactMap({ + ($0 as? HKQuantitySample)? + .quantity + .doubleValue(for: .gramUnit(with: .milli)) + } + ).reduce(0.0, +) + } +} diff --git a/caffeine/Services/HealthKit/HealthStoreService.swift b/caffeine/Services/HealthKit/HealthStoreService.swift new file mode 100644 index 0000000..95d9ac1 --- /dev/null +++ b/caffeine/Services/HealthKit/HealthStoreService.swift @@ -0,0 +1,152 @@ +import Foundation +import HealthKit + +class HealthStoreService { + static var shared: HealthStoreService = .init() + private let healthStore: HKHealthStore = .init() + + /// Readable data types from HealthKit + private var readDataTypes: Set { + if let caffeine = HKObjectType.quantityType(forIdentifier: .dietaryCaffeine), + let dateOfBirth = HKObjectType.characteristicType(forIdentifier: .dateOfBirth) { + + return .init([caffeine, dateOfBirth]) + } else { + return .init() + } + } + + /// Writable data types from HealthKit + private var writeDataTypes: Set { + if let caffeine = HKObjectType.quantityType(forIdentifier: .dietaryCaffeine) { + return .init([caffeine]) + } else { + return .init() + } + } + + private init() { } + + func requestPermission(completion: (() -> Void)? = nil) { + // Request permissions for the HKHealthStore object + HealthStoreService.shared.healthStore.requestAuthorization( + toShare: writeDataTypes, + read: readDataTypes + ) { [weak self] (success, error) in + guard success else { + print("You didn't allow HealthKit to access these read/write data types.") + print("In your app, try to handle this error gracefully when a user decides not to provide access.") + print("The error was: \(error?.localizedDescription ?? "unknown"). If you're using a simulator, try it on a device.") + return + } + + self?.refreshAge() + completion?() + } + } + + func refreshAge() { + do { + guard let birthday = try HealthStoreService.shared.healthStore + .dateOfBirthComponents().date else { + return + } + let ageComponents = Calendar.current.dateComponents( + [.year], + from: birthday, + to: .init() + ) + guard let age = ageComponents.year else { + return + } + + UserSettings.userAge = age + } catch { + print(NSLocalizedString("LoadAgeError", comment: "Something went wrong!")) + } + } + + /* + * + * Get a Consumption Object and save its Data as Quantity Sample + * into the Health Application. + * + */ + func storeConsumedObjectIntoHealth(_ consumption: ConsumableProperties) { + + let now: Date = Date() + let metaData = [HKMetadataKeyFoodType: consumption.title] + + guard let hkcaffeine: HKQuantityType = .quantityType( + forIdentifier: HKQuantityTypeIdentifier.dietaryCaffeine + ) else { + return + } + + if healthStore.authorizationStatus(for: hkcaffeine) == HKAuthorizationStatus.sharingAuthorized + && consumption.caffeine > 0.0 { + + let hkcaffeineQuantity: HKQuantity = .init( + unit: .gramUnit(with: .milli), + doubleValue: consumption.caffeine + ) + let hkcaffeineSample: HKQuantitySample = .init( + type: hkcaffeine, + quantity: hkcaffeineQuantity, + start: now, + end: now, + metadata: metaData + ) + healthStore.save( + hkcaffeineSample, + withCompletion: { _, _ in } + ) + } + } + + internal func loadConsumedData( + for period: Period, + completion: @escaping (Bool, [HKSample]) -> Void + ) { + loadConsumedData( + since: .init(timeIntervalSinceNow: -period.inSeconds), + completion: completion + ) + } + + private func loadConsumedData( + since startDate: Date, + until endDate: Date = .init(), + completion: @escaping (Bool, [HKSample]) -> Void + ) { + guard let caffeineType = HKQuantityType.quantityType(forIdentifier: .dietaryCaffeine) else { + return completion(false, []) + } + + let timeSortDescriptor: NSSortDescriptor = NSSortDescriptor( + key: HKSampleSortIdentifierEndDate, + ascending: false + ) + + let predicate = HKQuery.predicateForSamples( + withStart: startDate, + end: endDate, + options: HKQueryOptions() + ) + + let query = HKSampleQuery( + sampleType: caffeineType, + predicate: predicate, + limit: 0, + sortDescriptors: [timeSortDescriptor], + resultsHandler: { (_, result, error) in + guard error == nil, let result = result else { + return completion(false, []) + } + + completion(true, result) + } + ) + healthStore.execute(query) + } +} diff --git a/caffeine/Styling/CaffeineColors.swift b/caffeine/Styling/CaffeineColors.swift new file mode 100644 index 0000000..e720765 --- /dev/null +++ b/caffeine/Styling/CaffeineColors.swift @@ -0,0 +1,66 @@ +import UIKit + +enum CaffeineColors { + case consumptionButton + case graph + case inputButton + case selectIcon + case statsSeparatorStart + case statsSeparatorEnd + + var color: UIColor { + switch self { + case .consumptionButton: + return ColorScheme.primary.color + case .graph: + return ColorScheme.primary.color + case .inputButton: + return ColorScheme.secondary.color + case .selectIcon: + return ColorScheme.secondary.color + case .statsSeparatorStart: + return UIColor(red: 48.0 / 255.0, green: 48.0 / 255.0, blue: 48.0 / 255.0, alpha: 1.0) + case .statsSeparatorEnd: + return UIColor(red: 30.0 / 255.0, green: 29.0 / 255.0, blue: 34.0 / 255.0, alpha: 1.0) + } + } +} + +private enum ColorScheme { + case primary + case secondary + case tertiary + case quaternary + case quinary + case background + + var color: UIColor { + switch self { + case .primary: + return HexColors.gold.color + case .secondary: + return HexColors.green.color + case .tertiary: + return HexColors.blue.color + case .quaternary: + return HexColors.pink.color + case .quinary: + return HexColors.purple.color + case .background: + return HexColors.darkGray.color + } + } +} + +private enum HexColors: String { + case gold = "FEEBB3" + case green = "36D193" + case blue = "B3FEFB" + case pink = "FEB3F3" + case purple = "B3B8FE" + case darkGray = "35363A" + + var color: UIColor { + return .init(hex: self.rawValue) + } +} diff --git a/caffeine/Supporting Files/Base.lproj/Localizable.strings b/caffeine/Supporting Files/Base.lproj/Localizable.strings new file mode 100644 index 0000000..a197d4d --- /dev/null +++ b/caffeine/Supporting Files/Base.lproj/Localizable.strings @@ -0,0 +1,79 @@ +/* + * + * Copyright (C) Kayos UG (haftungsbeschränkt) - All Rights Reserved + * Unauthorized copying of this file, via any medium is strictly prohibited + * Proprietary and confidential + * + * NOTICE: All information contained herein is, and remains + * the property of Kayos UG (haftungsbeschränkt) and its suppliers, + * if any. The intellectual and technical concepts contained + * herein are proprietary to Kayos UG (haftungsbeschränkt) + * and its suppliers and are protected by trade secret or copyright law. + * Dissemination of this information or reproduction of this material + * is strictly forbidden unless prior written permission is obtained + * from Kayos UG (haftungsbeschränkt). + * + * Written by Simon Christian Krüger , October 2015 + * + */ + + +// App Strings +"ConsumptionTitle" = "A nice hot cup of coffee"; + +// Modell Strings +"SensibilityAlertTitle" = "Sensibility Updated"; +"SensibilityAlertBody" = "Please check your statistics and upate your personal data."; +"LoadAgeError" = "An Error occurd during Age loading. Please check your Health authorizations!"; + +// Shortcut Allert +"ShortcutHeading" = "Coffee Saved!"; +"ShortcutText" = "We updated your Statistics. Take a look."; +"ShortcutOK" = "OK"; + +// Days +"Monday" = "MO"; +"Tuesday" = "TU"; +"Wednesday" = "WE"; +"Thursday" = "TH"; +"Friday" = "FR"; +"Saturday" = "SA"; +"Sunday" = "SU"; + +// Months +"January" = "JAN"; +"February" = "FEB"; +"March" = "MAR"; +"April" = "APR"; +"May" = "MAY"; +"June" = "JUNE"; +"July" = "JULY"; +"August" = "AUG"; +"September" = "SEPT"; +"October" = "OCT"; +"November" = "NOV"; +"December" = "DEC"; + +// Shots +"noshot" = "No Coffee"; +"singleshot" = "1 Shot"; +"doubleshot" = "2 Shots"; +"tripleshot" = "3 Shots"; + +// Milk +"black" = "No Milk"; +"lactosefree" = "Lactose Free"; +"fullfat" = "Whole Milk"; +"soymilk" = "Soy Milk"; + +// Size +"nosize" = "Espresso Cup"; +"small" = "Small Cup"; +"medium" = "Medium Cup"; +"large" = "Large Cup"; + +// Sugar +"nosugar" = "No Sugar"; +"singlepiece" = "1 Sugar"; +"twopiece" = "2 Sugar"; +"threepiece" = "3 Sugar"; diff --git a/caffeine/Supporting Files/CaffeineDataDescription.rtf b/caffeine/Supporting Files/CaffeineDataDescription.rtf new file mode 100644 index 0000000..b1a1dec --- /dev/null +++ b/caffeine/Supporting Files/CaffeineDataDescription.rtf @@ -0,0 +1,21 @@ +{\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf470 +{\fonttbl\f0\fnil\fcharset0 Menlo-Regular;\f1\fnil\fcharset0 Menlo-Bold;} +{\colortbl;\red255\green255\blue255;} +\margl1440\margr1440\vieww9000\viewh8400\viewkind0 +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\partightenfactor0 + +\f0\fs22 \cf0 "The Half Life of Caffeine in healthy adults is about 5.7 hours"[1].\ +"However, at higher doses (e.g. 250\'96500mg single dose), the clearance of caffeine is significantly reduced and its elimination half-life is prolonged, indicating non-linearity"[2]\ +"The t1/2 (beta) was significantly prolonged in women on OCS (10.7 +/- 3.0 hr vs. 6.2 +/- 1.6)"[3]\ +\ + +\f1\b These three Predicates are the base of our caffeine calculation.\ +\ + +\f0\b0 First of all we have to determine the amount of ingested caffeine. According to Source[2] the t1/2 can be described by a non linear function. At the Moment my solution is indeed deterministic, but not reliable at all. The current calculation returns a value between 20270 seconds and 32000 seconds to halve a ingested dose of caffeine.\ +\ +\ +Sources:\ +[1]: {\field{\*\fldinst{HYPERLINK "http://www.ncbi.nlm.nih.gov/pubmed/7361718?dopt=Abstract"}}{\fldrslt http://www.ncbi.nlm.nih.gov/pubmed/7361718?dopt=Abstract}}\ +[2]: {\field{\*\fldinst{HYPERLINK "http://www.militaryenergygum.com/wp-content/uploads/Multiple-Dose-Pharmacokinetics.pdf"}}{\fldrslt http://www.militaryenergygum.com/wp-content/uploads/Multiple-Dose-Pharmacokinetics.pdf}}\ +[3]: {\field{\*\fldinst{HYPERLINK "http://www.ncbi.nlm.nih.gov/pubmed/7359014"}}{\fldrslt http://www.ncbi.nlm.nih.gov/pubmed/7359014}}} \ No newline at end of file diff --git a/caffeine/Supporting Files/Consumption/Coffee.plist b/caffeine/Supporting Files/Consumption/Coffee.plist new file mode 100644 index 0000000..df4eb1d --- /dev/null +++ b/caffeine/Supporting Files/Consumption/Coffee.plist @@ -0,0 +1,110 @@ + + + + + + title + noShot + volume + 0 + hkcaffeine + 0 + hkenergyCalories + 0 + hkfat + 0 + hksaturatedFat + 0 + hkunsaturatedFat + 0 + hksodium + 0 + hkpotassium + 0 + hkcarbs + 0 + hksugar + 0 + hkprotein + 0 + + + title + singleShot + volume + 33 + hkcaffeine + 70.66 + hkenergyCalories + 3 + hkfat + 0.06 + hksaturatedFat + 0.03 + hkunsaturatedFat + 0.03 + hksodium + 4.67 + hkpotassium + 38.3 + hkcarbs + 0.5600000000000001 + hksugar + 0 + hkprotein + 0.033 + + + title + doubleShot + volume + 66 + hkcaffeine + 141.33 + hkenergyCalories + 6 + hkfat + 0.13 + hksaturatedFat + 0.065 + hkunsaturatedFat + 0.065 + hksodium + 9.33 + hkpotassium + 76.59999999999999 + hkcarbs + 1.13 + hksugar + 0 + hkprotein + 0.067 + + + title + tripleShot + volume + 100 + hkcaffeine + 212 + hkenergyCalories + 9 + hkfat + 0.2 + hksaturatedFat + 0.1 + hkunsaturatedFat + 0.1 + hksodium + 14 + hkpotassium + 115 + hkcarbs + 1.7 + hksugar + 0 + hkprotein + 0.1 + + + diff --git a/caffeine/Supporting Files/Consumption/Milk.plist b/caffeine/Supporting Files/Consumption/Milk.plist new file mode 100644 index 0000000..61d5d7d --- /dev/null +++ b/caffeine/Supporting Files/Consumption/Milk.plist @@ -0,0 +1,110 @@ + + + + + + title + black + volume + 0 + hkcaffeine + 0 + hkenergyCalories + 0 + hkfat + 0 + hksaturatedFat + 0 + hkunsaturatedFat + 0 + hksodium + 0 + hkpotassium + 0 + hkcarbs + 0 + hksugar + 0 + hkprotein + 0 + + + title + lactoseFree + volume + 100 + hkcaffeine + 0 + hkenergyCalories + 47 + hkfat + 1.5 + hksaturatedFat + 0.9 + hkunsaturatedFat + 0 + hksodium + 0.05 + hkpotassium + 0 + hkcarbs + 4.9 + hksugar + 4.9 + hkprotein + 3.4 + + + title + fullFat + volume + 100 + hkcaffeine + 0 + hkenergyCalories + 64 + hkfat + 3.5 + hksaturatedFat + 2.1 + hkunsaturatedFat + 0 + hksodium + 50 + hkpotassium + 150 + hkcarbs + 4.8 + hksugar + 2.8 + hkprotein + 3.3 + + + title + soyMilk + volume + 100 + hkcaffeine + 0 + hkenergyCalories + 54 + hkfat + 1.8 + hksaturatedFat + 0.2 + hkunsaturatedFat + 1 + hksodium + 51 + hkpotassium + 118 + hkcarbs + 6 + hksugar + 4 + hkprotein + 3.3 + + + diff --git a/caffeine/Supporting Files/Consumption/Size.plist b/caffeine/Supporting Files/Consumption/Size.plist new file mode 100644 index 0000000..47f0cfb --- /dev/null +++ b/caffeine/Supporting Files/Consumption/Size.plist @@ -0,0 +1,30 @@ + + + + + + title + noSize + volume + 0 + + + title + small + volume + 150 + + + title + medium + volume + 200 + + + title + large + volume + 250 + + + diff --git a/caffeine/Supporting Files/Consumption/Sugar.plist b/caffeine/Supporting Files/Consumption/Sugar.plist new file mode 100644 index 0000000..77f695b --- /dev/null +++ b/caffeine/Supporting Files/Consumption/Sugar.plist @@ -0,0 +1,110 @@ + + + + + + title + noSugar + volume + 0 + hkcaffeine + 0 + hkenergyCalories + 0 + hkfat + 0 + hksaturatedFat + 0 + hkunsaturatedFat + 0 + hksodium + 0 + hkpotassium + 0 + hkcarbs + 0 + hksugar + 0 + hkprotein + 0 + + + title + singlePiece + volume + 8 + hkcaffeine + 0 + hkenergyCalories + 32.25 + hkfat + 0 + hksaturatedFat + 0 + hkunsaturatedFat + 0 + hksodium + 0.08 + hkpotassium + 0.17 + hkcarbs + 8 + hksugar + 8 + hkprotein + 0 + + + title + twoPieces + volume + 16 + hkcaffeine + 0 + hkenergyCalories + 64.5 + hkfat + 0 + hksaturatedFat + 0 + hkunsaturatedFat + 0 + hksodium + 0.17 + hkpotassium + 0.33 + hkcarbs + 17 + hksugar + 17 + hkprotein + 0 + + + title + threePieces + volume + 24 + hkcaffeine + 0 + hkenergyCalories + 96.75 + hkfat + 0 + hksaturatedFat + 0 + hkunsaturatedFat + 0 + hksodium + 0.25 + hkpotassium + 0.5 + hkcarbs + 25 + hksugar + 25 + hkprotein + 0 + + + diff --git a/caffeine/Supporting Files/MindModellDesctiption.rtf b/caffeine/Supporting Files/MindModellDesctiption.rtf new file mode 100644 index 0000000..d638a0e --- /dev/null +++ b/caffeine/Supporting Files/MindModellDesctiption.rtf @@ -0,0 +1,44 @@ +{\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf130 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;\f1\fnil\fcharset0 LucidaGrande;} +{\colortbl;\red255\green255\blue255;} +{\*\listtable{\list\listtemplateid1\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{hyphen\}}{\leveltext\leveltemplateid1\'01\uc0\u8259 ;}{\levelnumbers;}\fi-360\li720\lin720 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{hyphen\}}{\leveltext\leveltemplateid2\'01\uc0\u8259 ;}{\levelnumbers;}\fi-360\li1440\lin1440 }{\listname ;}\listid1}} +{\*\listoverridetable{\listoverride\listid1\listoverridecount0\ls1}} +\margl1440\margr1440\vieww9000\viewh8400\viewkind0 +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\partightenfactor0 + +\f0\b\fs24 \cf0 Use the MindModell Class to setup a basic self minded decision system.\ + +\b0 \ +Relevant Data:\ + +\f1 \uc0\u9642 +\f0 Consumed Caffeine during the last week\ + +\f1 \uc0\u9642 +\f0 Blood / Caffeine Concentration during the last week\ + +\f1 \uc0\u9642 +\f0 How often did the user exceed the personal limit\ + +\f1 \uc0\u9642 +\f0 Current Sensibility Level\ + +\f1 \uc0\u9642 +\f0 Number of Entries using Caffeine\ +\ +1.) If no entries were made during the last 7 days give the user a bright reminder to use Caffeine for their data.\ +\pard\tx940\tx1440\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\li1440\fi-1440\pardirnatural\partightenfactor0 +\ls1\ilvl1\cf0 \uc0\u8259 suggest a higher sensibility, if the user does not consume any caffeine\ + - use as a reminder to manage caffeine data in our app \ +2.) The user consumed regularly caffeine products but don't usually exceed the limits\ + \uc0\u8259 don't change any Sensibility\ +3.) The user consumed irregularly caffeine products and exceeded the limits most of the time\ + \uc0\u8259 decrease the Sensibility just a bit\ + \uc0\u8259 use as a reminder to check life-work balance\ +4.) The user exceeded the limits regularly\ + - decrease the Sensibility\ + - try to approach the regularly consumed caffeine level\ +\ +\pard\tx940\tx1440\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\li1440\fi-1440\pardirnatural\partightenfactor0 +\ls1\ilvl1 +\b \cf0 Maybe the calculation has to be slightly adjusted to fit into these new requirements.} \ No newline at end of file diff --git a/caffeine/Supporting Files/de.lproj/Localizable.strings b/caffeine/Supporting Files/de.lproj/Localizable.strings new file mode 100644 index 0000000..b910050 --- /dev/null +++ b/caffeine/Supporting Files/de.lproj/Localizable.strings @@ -0,0 +1,79 @@ +/* + * + * Copyright (C) Kayos UG (haftungsbeschränkt) - All Rights Reserved + * Unauthorized copying of this file, via any medium is strictly prohibited + * Proprietary and confidential + * + * NOTICE: All information contained herein is, and remains + * the property of Kayos UG (haftungsbeschränkt) and its suppliers, + * if any. The intellectual and technical concepts contained + * herein are proprietary to Kayos UG (haftungsbeschränkt) + * and its suppliers and are protected by trade secret or copyright law. + * Dissemination of this information or reproduction of this material + * is strictly forbidden unless prior written permission is obtained + * from Kayos UG (haftungsbeschränkt). + * + * Written by Simon Christian Krüger , October 2015 + * + */ + + +// App Strings +"ConsumptionTitle" = "Eine schöne heiße Tasse Kaffee."; + +// Modell Strings +"SensibilityAlertTitle" = "Empfindlichkeit aktualisiert"; +"SensibilityAlertBody" = "Bitte überprüf deine Statistik und passe deine persönlichen Daten an."; +"LoadAgeError" = "Während des Ladeprozesses ist ein Fehler aufgetreten. Bitte überprüf deine Health Berechtigungen!"; + +// Shortcut Allert +"ShortcutHeading" = "Kaffee gespeichert!"; +"ShortcutText" = "Deine Statistik wurde aktualisiert. Schau mal rein."; +"ShortcutOK" = "OK"; + +// Days +"Monday" = "MO"; +"Tuesday" = "DI"; +"Wednesday" = "MI"; +"Thursday" = "DO"; +"Friday" = "FR"; +"Saturday" = "SA"; +"Sunday" = "SO"; + +// Months +"January" = "JAN"; +"February" = "FEB"; +"March" = "MÄR"; +"April" = "APR"; +"May" = "MAI"; +"June" = "JUNI"; +"July" = "JULI"; +"August" = "AUG"; +"September" = "SEPT"; +"October" = "OKT"; +"November" = "NOV"; +"December" = "DEZ"; + +// Shots +"noshot" = "Kein Kaffee"; +"singleshot" = "1 Shot"; +"doubleshot" = "2 Shots"; +"tripleshot" = "3 Shots"; + +// Milk +"black" = "Keine Milch"; +"lactosefree" = "Laktosefrei"; +"fullfat" = "Vollmilch"; +"soymilk" = "Sojamilch"; + +// Size +"nosize" = "Espresso Tasse"; +"small" = "Kleine Tasse"; +"medium" = "Mittlere Tasse"; +"large" = "Große Tasse"; + +// Sugar +"nosugar" = "Kein Zucker"; +"singlepiece" = "1 Zucker"; +"twopiece" = "2 Zucker"; +"threepiece" = "3 Zucker"; diff --git a/caffeine/View/UICaffeineConsumptionRecentButton.swift b/caffeine/View/UICaffeineConsumptionRecentButton.swift new file mode 100644 index 0000000..ff03afb --- /dev/null +++ b/caffeine/View/UICaffeineConsumptionRecentButton.swift @@ -0,0 +1,73 @@ +import Foundation +import UIKit + +class UICaffeineConsumptionRecentButton: UIButton { + @IBOutlet private weak var cupIcon: UIImageView! + @IBOutlet private weak var mainLabel: UILabel! + @IBOutlet private weak var subtitleLabel: UILabel! + + internal var shotState: Coffee = .noShot + internal var milkState: Milk = .black + internal var cupState: Size = .noSize + internal var sugarState: Sugar = .noSugar + + override init (frame: CGRect) { + super.init(frame: frame) + setUpView() + } + + convenience init () { + self.init(frame: CGRect.zero) + } + + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + setUpView() + } + + fileprivate func setUpView() { + self.layer.cornerRadius = 8.0 + self.layer.borderWidth = 0.0 + self.layer.borderColor = CaffeineColors.consumptionButton.color.cgColor + } + + func setConsumable(_ consumable: Consumable) { + shotState = consumable.coffee + milkState = consumable.milk + cupState = consumable.size + sugarState = consumable.sugar + + setRecentButtonAppearance() + } + + fileprivate func setRecentButtonAppearance() { + self.mainLabel.text = "\(shotState.localizedTitle), \(cupState.localizedTitle)" + self.subtitleLabel.text = "\(milkState.localizedTitle), \(sugarState.localizedTitle)" + self.cupIcon.image = UIImage(named: cupState.imageName) + } + + override func touchesBegan(_ touches: Set, with event: UIEvent?) { + super.touchesBegan(touches, with: event) + self.mainLabel.textColor = UIColor.darkGray + self.subtitleLabel.textColor = UIColor.darkGray + self.cupIcon.image = UIImage(named: cupState.imageNameSelected) + self.layer.borderColor = UIColor.darkGray.cgColor + } + + override func touchesEnded(_ touches: Set, with event: UIEvent?) { + super.touchesEnded(touches, with: event) + self.mainLabel.textColor = CaffeineColors.consumptionButton.color + self.subtitleLabel.textColor = UIColor.white + self.cupIcon.image = UIImage(named: cupState.imageName) + self.layer.borderColor = CaffeineColors.consumptionButton.color.cgColor + } + + override func touchesCancelled(_ touches: Set, with event: UIEvent?) { + super.touchesCancelled(touches, with: event) + self.mainLabel.textColor = CaffeineColors.consumptionButton.color + self.subtitleLabel.textColor = UIColor.white + self.cupIcon.image = UIImage(named: cupState.imageName) + self.layer.borderColor = CaffeineColors.consumptionButton.color.cgColor + } + +} diff --git a/caffeine/View/UICaffeineInputButton.swift b/caffeine/View/UICaffeineInputButton.swift new file mode 100644 index 0000000..7a96309 --- /dev/null +++ b/caffeine/View/UICaffeineInputButton.swift @@ -0,0 +1,51 @@ +import Foundation +import UIKit +import Spring + +struct UICaffeineInputButtonViewModel { + let inputIconImage: UIImage + let selectIconImage: UIImage + let descriptionLabelText: String? +} + +class UICaffeineInputButton: UIButton { + @IBOutlet private weak var inputIcon: DesignableImageView? + @IBOutlet private weak var selectIcon: SpringImageView? + @IBOutlet private weak var descriptionLabel: UILabel? + + func tapAnimation(_ animated: Bool) { + guard + let selectIcon = self.selectIcon, + let inputIcon = self.inputIcon + else { + return + } + + selectIcon.isHidden = !selectIcon.isHidden + backgroundColor = selectIcon.isHidden ? UIColor( + red: 0.16, + green: 0.16, + blue: 0.17, + alpha: 0 + ) : UIColor( + red: 0.16, + green: 0.16, + blue: 0.17, + alpha: 1 + ) + + if animated == true { + inputIcon.scaleX = 1.5 + inputIcon.scaleY = 1.5 + inputIcon.curve = "spring" + inputIcon.duration = 1.2 + inputIcon.animate() + + selectIcon.animation = "fadeIn" + selectIcon.curve = "spring" + + selectIcon.duration = 1.3 + selectIcon.animate() + } + } +} diff --git a/caffeine/View/UICaffeineInputButtonView.swift b/caffeine/View/UICaffeineInputButtonView.swift new file mode 100644 index 0000000..87a132f --- /dev/null +++ b/caffeine/View/UICaffeineInputButtonView.swift @@ -0,0 +1,23 @@ +import Foundation +import UIKit + +class UICaffeineInputButtonView: UIView { + + override init (frame: CGRect) { + super.init(frame: frame) + setUpView() + } + + convenience init () { + self.init(frame: CGRect.zero) + } + + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + setUpView() + } + + func setUpView () { + + } +} diff --git a/caffeine/View/UICaffeineInputOKButton.swift b/caffeine/View/UICaffeineInputOKButton.swift new file mode 100644 index 0000000..7e4bbab --- /dev/null +++ b/caffeine/View/UICaffeineInputOKButton.swift @@ -0,0 +1,50 @@ +import Foundation +import UIKit + +extension UIColor { + func image(_ size: CGSize = CGSize(width: 1, height: 1)) -> UIImage { + return UIGraphicsImageRenderer(size: size).image { rendererContext in + self.setFill() + rendererContext.fill(CGRect(origin: .zero, size: size)) + } + } +} + +class UICaffeineInputOKButton: UIButton { + + override init (frame: CGRect) { + super.init(frame: frame) + setUpView() + } + + convenience init () { + self.init(frame: CGRect.zero) + } + + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + setUpView() + } + + fileprivate func setUpView() { + layer.cornerRadius = 10.0 + layer.borderWidth = 1.0 + + setTitleColor(UIColor.lightGray, for: .disabled) + setTitleColor(CaffeineColors.inputButton.color, for: .highlighted) + setBackgroundImage(UIColor.clear.image(), for: .disabled) + setBackgroundImage(UIColor.clear.image(), for: .highlighted) + + makeButtonNotSelectable() + } + + internal func makeButtonSelectable() { + self.layer.borderColor = CaffeineColors.inputButton.color.cgColor + self.isEnabled = true + } + + internal func makeButtonNotSelectable() { + self.layer.borderColor = UIColor.lightGray.cgColor + self.isEnabled = false + } +} diff --git a/caffeine/View/UICaffeineSlider.swift b/caffeine/View/UICaffeineSlider.swift new file mode 100644 index 0000000..cfaf505 --- /dev/null +++ b/caffeine/View/UICaffeineSlider.swift @@ -0,0 +1,30 @@ +import Foundation +import UIKit + +class UICaffeineSlider: UISlider { + @IBOutlet private(set) weak var sliderPopupView: UISliderPopupView? + + internal var sliderType: SliderType? { + didSet { + minimumValue = sliderType?.sliderMin ?? 0.0 + maximumValue = sliderType?.sliderMax ?? 100.0 + } + } + + internal func updateSliderPopup() { + let formatter = NumberFormatter() + formatter.numberStyle = NumberFormatter.Style.decimal + formatter.maximumFractionDigits = 0 + guard let text = formatter.string(from: .init(value: value)) else { return } + + if (sliderType == SliderType.weight) { + sliderPopupView?.setLabel(text: "\(text) kg") + + } else if (sliderType == SliderType.height) { + sliderPopupView?.setLabel(text: "\(text) cm") + + } else if (sliderType == SliderType.sensibility) { + sliderPopupView?.setLabel(text: "\(text) %") + } + } +} diff --git a/caffeine/View/UICaffeineStatisticsChartView.swift b/caffeine/View/UICaffeineStatisticsChartView.swift new file mode 100644 index 0000000..e1d82f1 --- /dev/null +++ b/caffeine/View/UICaffeineStatisticsChartView.swift @@ -0,0 +1,243 @@ +import Foundation +import UIKit + +/* +* +* This View will display the Caffeine Blod Concentration over a given period of time. +* Above that it could be possible to change the time eg. 12h, 24h, 48h. +* Maybe more statistical relevant content like how much milk, coffee, sugar was consumed +* during the last 30 days. +* +*/ + +class UICaffeineStatisticsChartView: UIView { + private var items: [Double] = [] + private var catmullRom: Bool = true + private var objectCounter: Int { + return items.count + } + private var intersectDistance: Int = 4 + + override init (frame: CGRect) { + super.init(frame: frame) + } + + convenience init () { + self.init(frame: CGRect.zero) + } + + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + } + + override func draw(_ rect: CGRect) { + if !items.isEmpty { + // margin-left && margin-right + let margin: CGFloat = 20.0 + let topBorder: CGFloat = 10 + let bottomBorder: CGFloat = 40 + let graphBorder: CGFloat = 30 + let graphHeight = rect.height - topBorder - bottomBorder - graphBorder + + let spacer = (rect.width - margin * 2) / CGFloat((items.count - 1)) + let maxValue: Int = Int(items.max() ?? 0.0) + + let columnXPoint = { (column: Int) -> CGFloat in + var x: CGFloat = CGFloat(column) * spacer + x += margin + return x + } + let columnYPoint = { (graphPoint: Int) -> CGFloat in + var y: CGFloat = CGFloat(graphPoint) / CGFloat(maxValue) * graphHeight + y = graphHeight + topBorder + graphBorder - y // Flip the graph + return y + } + + for index: Int in 0.. CGPoint { + return CGPoint(x: self.x + x, y: self.y + y) + } + + func translateX(_ x: CGFloat) -> CGPoint { + return CGPoint(x: self.x + x, y: self.y) + } + + func translateY(_ y: CGFloat) -> CGPoint { + return CGPoint(x: self.x, y: self.y + y) + } + + func invertY() -> CGPoint { + return CGPoint(x: self.x, y: -self.y) + } + + func xAxis() -> CGPoint { + return CGPoint(x: 0, y: self.y) + } + + func yAxis() -> CGPoint { + return CGPoint(x: self.x, y: 0) + } + + func addTo(_ a: CGPoint) -> CGPoint { + return CGPoint(x: self.x + a.x, y: self.y + a.y) + } + + func deltaTo(_ a: CGPoint) -> CGPoint { + return CGPoint(x: self.x - a.x, y: self.y - a.y) + } + + func multiplyBy(_ value: CGFloat) -> CGPoint { + return CGPoint(x: self.x * value, y: self.y * value) + } + + func length() -> CGFloat { + return CGFloat( + sqrt( + CDouble( + self.x * self.x + self.y * self.y + ) + ) + ) + } + + func normalize() -> CGPoint { + let l = self.length() + return CGPoint(x: self.x / l, y: self.y / l) + } + + static func fromString(_ string: String) -> CGPoint { + var s = string.replacingOccurrences(of: "{", with: "") + s = s.replacingOccurrences(of: "}", with: "") + s = s.replacingOccurrences(of: " ", with: "") + + let x = NSString(string: s.components(separatedBy: ",").first! as String).doubleValue + let y = NSString(string: s.components(separatedBy: ",").last! as String).doubleValue + + return CGPoint(x: CGFloat(x), y: CGFloat(y)) + } +} diff --git a/caffeine/View/UICaffeineStatisticsTimeSelectorView.swift b/caffeine/View/UICaffeineStatisticsTimeSelectorView.swift new file mode 100644 index 0000000..27729a2 --- /dev/null +++ b/caffeine/View/UICaffeineStatisticsTimeSelectorView.swift @@ -0,0 +1,59 @@ +import Foundation +import UIKit + +enum SelectorState: Int { + case day + case week + case month + case year +} + +class UICaffeineStatisticsTimeSelectorView: UIView { + @IBOutlet private weak var dayButton: UIButton? + @IBOutlet private weak var weekButton: UIButton? + @IBOutlet private weak var monthButton: UIButton? + @IBOutlet private weak var yearButton: UIButton? + @IBOutlet private weak var dayIndicatorView: UIView? + @IBOutlet private weak var weekIndicatorView: UIView? + @IBOutlet private weak var monthIndicatorView: UIView? + @IBOutlet private weak var yearIndicatorView: UIView? + private var selectorState: SelectorState = .day + + override init (frame: CGRect) { + super.init(frame: frame) + } + + convenience init () { + self.init(frame: CGRect.zero) + } + + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + } + + fileprivate func updateIndicatorState() { + for indicator in [ + dayIndicatorView, + weekIndicatorView, + monthIndicatorView, + yearIndicatorView + ] { + indicator?.isHidden = true + } + switch selectorState { + case .day: + dayIndicatorView?.isHidden = false + case .week: + weekIndicatorView?.isHidden = false + case .month: + monthIndicatorView?.isHidden = false + case .year: + yearIndicatorView?.isHidden = false + } + } + + func buttonTapped(with selectorState: SelectorState) { + self.selectorState = selectorState + updateIndicatorState() + } +} diff --git a/caffeine/View/UISliderPopupView.swift b/caffeine/View/UISliderPopupView.swift new file mode 100644 index 0000000..fbb8daf --- /dev/null +++ b/caffeine/View/UISliderPopupView.swift @@ -0,0 +1,10 @@ +import Foundation +import UIKit + +class UISliderPopupView: UIView { + @IBOutlet private weak var popUpLabel: UILabel? + + func setLabel(text: String?) { + popUpLabel?.text = text + } +} diff --git a/caffeine/ViewController/ConsumptionViewController.swift b/caffeine/ViewController/ConsumptionViewController.swift new file mode 100644 index 0000000..46fb6a1 --- /dev/null +++ b/caffeine/ViewController/ConsumptionViewController.swift @@ -0,0 +1,83 @@ +import Foundation +import UIKit + +class ConsumptionViewController: UIViewController { + + @IBOutlet private weak var todayCaffeineLabel: UILabel? + @IBOutlet private weak var maximumCaffeineLabel: UILabel? + + @IBOutlet private weak var firstButton: UICaffeineConsumptionRecentButton? + @IBOutlet private weak var secondButton: UICaffeineConsumptionRecentButton? + @IBOutlet private weak var thirdButton: UICaffeineConsumptionRecentButton? + + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + + reloadData() + + HealthStoreService.shared.requestPermission { [weak self] in + self?.reloadData() + } + } + + private func reloadData() { + DispatchQueue.main.async( + execute: { [weak self] () -> Void in + let healthyAmount = Int(round(CaffeineDataService.shared.healthyAmount() ?? 0.0)) + self?.maximumCaffeineLabel?.text = "\(healthyAmount)" + + let recentConsumables = DrinksService.shared.getRecentDrinks() + self?.firstButton?.setConsumable(recentConsumables[0]) + self?.secondButton?.setConsumable(recentConsumables[1]) + self?.thirdButton?.setConsumable(recentConsumables[2]) + } + ) + + CaffeineDataService.shared.getCaffeineConsumption { [weak self] (success, caffeineReturn) -> Void in + guard success, let caffeineReturn = caffeineReturn else { return } + DispatchQueue.main.async( + execute: { () -> Void in + self?.todayCaffeineLabel?.text = "\(Int(round(caffeineReturn)))" + } + ) + } + } + + @IBAction private func firstButtonTouchUpInside(_ sender: Any?) { + recentButtonTouch(0) + } + + @IBAction private func secondButtonTouchUpInside(_ sender: Any?) { + recentButtonTouch(1) + } + + @IBAction private func thirdButtonTouchUpInside(_ sender: Any?) { + recentButtonTouch(2) + } + + private func recentButtonTouch(_ recent: Int) { + let recentConsumables = DrinksService.shared.getRecentDrinks() + let recentConsumable = recentConsumables[recent] + DrinksService.shared.drink(recentConsumable) + + let alertController = UIAlertController( + title: "\(NSLocalizedString("ShortcutHeading", comment: ""))", + message: NSLocalizedString("ShortcutText", comment: ""), + preferredStyle: .alert + ) + + let okAction = UIAlertAction( + title: NSLocalizedString("ShortcutOK", comment: ""), + style: .default, + handler: nil + ) + alertController.addAction(okAction) + + present( + alertController, + animated: true, + completion: reloadData + ) + } + +} diff --git a/caffeine/ViewController/InputViewController.swift b/caffeine/ViewController/InputViewController.swift new file mode 100644 index 0000000..64475c7 --- /dev/null +++ b/caffeine/ViewController/InputViewController.swift @@ -0,0 +1,200 @@ +import Foundation +import UIKit +import Spring + +/* +* +* Use this ViewController to call the "calculateHKValuesForSetup(coffee:Coffee, milk:Milk, size:Size, sugar:Sugar)" +* function on a ConsumptionObject. The user can select the designated drinks and a button is activated. +* +* TODO: Safe consumed Drinks of last 30 Days for statistical Purpose. +* +*/ + +class InputViewController: UIViewController { + private var shotState: Coffee = .noShot + private var milkState: Milk = .black + private var cupState: Size = .noSize + private var sugarState: Sugar = .noSugar + + private var shotSender: UICaffeineInputButton? + private var milkSender: UICaffeineInputButton? + private var cupSender: UICaffeineInputButton? + private var sugarSender: UICaffeineInputButton? + + @IBOutlet var inputOKButton: UICaffeineInputOKButton? + + // MARK: Input Shot, Milk, Cupsize and Sugar IBActions + @IBAction private func oneShotIconClicked(_ sender: UICaffeineInputButton) { + changeCoffeeState(sender, state: .singleShot) + } + + @IBAction private func twoShotIconClicked(_ sender: UICaffeineInputButton) { + changeCoffeeState(sender, state: .doubleShot) + } + + @IBAction private func threeShotIconClicked(_ sender: UICaffeineInputButton) { + changeCoffeeState(sender, state: .tripleShot) + } + + @IBAction private func lactosefreeMilkIconClicked(_ sender: UICaffeineInputButton) { + changeMilkState(sender, state: .lactoseFree) + } + + @IBAction private func wholeMilkIconClicked(_ sender: UICaffeineInputButton) { + changeMilkState(sender, state: .fullFat) + } + + @IBAction private func soyMIlkIconClicked(_ sender: UICaffeineInputButton) { + changeMilkState(sender, state: .soyMilk) + } + + @IBAction private func smallIconClicked(_ sender: UICaffeineInputButton) { + changeCupState(sender, state: .small) + } + + @IBAction private func middleIconClicked(_ sender: UICaffeineInputButton) { + changeCupState(sender, state: .medium) + } + + @IBAction private func largeIconClicked(_ sender: UICaffeineInputButton) { + changeCupState(sender, state: .large) + } + + @IBAction private func oneSugarIconClicked(_ sender: UICaffeineInputButton) { + changeSugarState(sender, state: .singlePiece) + } + + @IBAction private func twoSugarIconClicked(_ sender: UICaffeineInputButton) { + changeSugarState(sender, state: .twoPieces) + } + + @IBAction private func threeSugarIconClicked(_ sender: UICaffeineInputButton) { + changeSugarState(sender, state: .threePieces) + } + + @IBAction private func inputOKButtonClicked(_ sender: UICaffeineInputOKButton) { + // TODO: TapticEngine Vibration after Swift/iOS Update + + DrinksService.shared.drink( + .init( + coffee: shotState, + milk: milkState, + size: cupState, + sugar: sugarState, + date: .init() + ) + ) + + if shotState != .noShot { + buttonTap(shotSender, animated: true) + shotState = .noShot + } + if milkState != .black { + buttonTap(milkSender, animated: true) + milkState = .black + } + if cupState != .noSize { + buttonTap(cupSender, animated: true) + cupState = .noSize + } + if sugarState != .noSugar { + buttonTap(sugarSender, animated: true) + sugarState = .noSugar + } + checkInputOKButtonState() + } + + // MARK: State Machine + private func changeCoffeeState(_ sender: UICaffeineInputButton, state: Coffee) { + if shotState == .noShot { + shotSender = sender + shotState = state + } else { + if shotState == state { + shotState = .noShot + } else { + buttonTap(shotSender) + shotSender = sender + shotState = state + } + } + buttonTap(sender, animated: true) + checkInputOKButtonState() + } + + private func changeMilkState(_ sender: UICaffeineInputButton, state: Milk) { + if milkState == .black { + milkSender = sender + milkState = state + } else { + if milkState == state { + milkState = .black + } else { + buttonTap(milkSender) + milkSender = sender + milkState = state + } + } + buttonTap(sender, animated: true) + checkInputOKButtonState() + } + + private func changeCupState(_ sender: UICaffeineInputButton, state: Size) { + if cupState == .noSize { + cupSender = sender + cupState = state + } else { + if cupState == state { + cupState = .noSize + } else { + buttonTap(cupSender) + cupSender = sender + cupState = state + } + } + buttonTap(sender, animated: true) + checkInputOKButtonState() + } + + private func changeSugarState(_ sender: UICaffeineInputButton, state: Sugar) { + if sugarState == .noSugar { + sugarSender = sender + sugarState = state + } else { + if sugarState == state { + sugarState = .noSugar + } else { + buttonTap(sugarSender) + sugarSender = sender + sugarState = state + } + } + buttonTap(sender, animated: true) + checkInputOKButtonState() + } + + // Button Logic + private func checkInputOKButtonState() { + if shotState != .noShot { + inputOKButton?.makeButtonSelectable() + } else { + if milkState != .black && cupState != .noSize { + inputOKButton?.makeButtonSelectable() + } else { + inputOKButton?.makeButtonNotSelectable() + } + } + } + + // MARK: Button Tap handler + + private func buttonTap(_ sender: UICaffeineInputButton?) { + buttonTap(sender, animated: false) + } + + private func buttonTap(_ sender: UICaffeineInputButton?, animated: Bool) { + guard let sender = sender else { return } + sender.tapAnimation(animated) + } +} diff --git a/caffeine/ViewController/SettingsViewController.swift b/caffeine/ViewController/SettingsViewController.swift new file mode 100644 index 0000000..0c7c40f --- /dev/null +++ b/caffeine/ViewController/SettingsViewController.swift @@ -0,0 +1,162 @@ +import Foundation +import UIKit + +internal enum SliderType { + case weight + case height + case sensibility + case sex + + var sliderMin: Float { + switch self { + case .weight: + return 0 + case .height: + return 0 + case .sensibility: + return 0 + case .sex: + return 0 + } + } + + var sliderMax: Float { + switch self { + case .weight: + return 150 + case .height: + return 225 + case .sensibility: + return 100 + case .sex: + return 100 + } + } +} + +/* +* +* Use this ViewController to modify the Personal data Values: +* - Weight +* - Body height +* - Gender +* - Caffeine Sensibility +* - oral contraceptives consumption +* +* Also use this Controller for pushing, when the Application is launched for +* the first time. All Data is Modified via a DataManager Object. +* +* +*/ +class SettingsViewController: UIViewController { + @IBOutlet private weak var weigthSlider: UICaffeineSlider? + @IBOutlet private weak var heightSlider: UICaffeineSlider? + @IBOutlet private weak var sensibilitySlider: UICaffeineSlider? + @IBOutlet private weak var sexSlider: UICaffeineSlider? + @IBOutlet private weak var oralContraceptivesSwitch: UISwitch? + + private var weightConst: NSLayoutConstraint = .init() + private var heightConst: NSLayoutConstraint = .init() + private var sensibilityConst: NSLayoutConstraint = .init() + + override func viewDidLoad() { + super.viewDidLoad() + setupSlider() + } + + private func setupSlider() { + weigthSlider?.sliderType = .weight + heightSlider?.sliderType = .height + sensibilitySlider?.sliderType = .sensibility + sexSlider?.sliderType = .sex + + weigthSlider?.value = Float(UserSettings.userWeight) + heightSlider?.value = Float(UserSettings.userHeight) + sensibilitySlider?.value = Float(UserSettings.userSensibility) + sexSlider?.value = Float(UserSettings.userSex) + oralContraceptivesSwitch?.setOn(UserSettings.userSteroids, animated: false) + + weightConst = NSLayoutConstraint( + item: (weigthSlider?.sliderPopupView)!, + attribute: NSLayoutConstraint.Attribute.centerX, + relatedBy: NSLayoutConstraint.Relation.equal, + toItem: view, + attribute: NSLayoutConstraint.Attribute.centerX, + multiplier: 1, + constant: 0 + ) + heightConst = NSLayoutConstraint( + item: (heightSlider?.sliderPopupView)!, + attribute: NSLayoutConstraint.Attribute.centerX, + relatedBy: NSLayoutConstraint.Relation.equal, + toItem: view, + attribute: NSLayoutConstraint.Attribute.centerX, + multiplier: 1, + constant: 0 + ) + sensibilityConst = NSLayoutConstraint( + item: (sensibilitySlider?.sliderPopupView)!, + attribute: NSLayoutConstraint.Attribute.centerX, + relatedBy: NSLayoutConstraint.Relation.equal, + toItem: view, + attribute: NSLayoutConstraint.Attribute.centerX, + multiplier: 1, + constant: 0 + ) + + view.addConstraint(weightConst) + view.addConstraint(heightConst) + view.addConstraint(sensibilityConst) + updatePopup() + } + + private func updatePopup() { + weigthSlider?.updateSliderPopup() + heightSlider?.updateSliderPopup() + sensibilitySlider?.updateSliderPopup() + + weightConst.constant = getNewConstantPositionForSender(weigthSlider) + heightConst.constant = getNewConstantPositionForSender(heightSlider) + sensibilityConst.constant = getNewConstantPositionForSender(sensibilitySlider) + } + + // TODO: Change Data via UserManager Class + // MARK: Slider and Button Actions + + @IBAction private func weightSliderValueChanged(_ sender: UICaffeineSlider) { + sender.updateSliderPopup() + weightConst.constant = self.getNewConstantPositionForSender(sender) + UserSettings.userWeight = Int(round(sender.value)) + } + + @IBAction private func heightSliderValueChanged(_ sender: UICaffeineSlider) { + sender.updateSliderPopup() + heightConst.constant = self.getNewConstantPositionForSender(sender) + UserSettings.userHeight = Int(round(sender.value)) + } + + @IBAction private func sensibilitySliderValueChaged(_ sender: UICaffeineSlider) { + sender.updateSliderPopup() + sensibilityConst.constant = self.getNewConstantPositionForSender(sender) + UserSettings.userSensibility = Int(round(sender.value)) + } + + @IBAction private func sexSliderValueChaged(_ sender: UICaffeineSlider) { + sender.updateSliderPopup() + UserSettings.userSex = Int(round(sender.value)) + } + + @IBAction private func oralContraceptivesSwitchValueChanged(_ sender: UISwitch) { + UserSettings.userSteroids = sender.isOn + } + + private func getNewConstantPositionForSender(_ sender: UICaffeineSlider?) -> CGFloat { + guard let sender = sender else { return 0.0 } + let valueMargin = sender.maximumValue - sender.minimumValue + let differenceFromRefferencepoint = Double(sender.value - ((valueMargin / 2) + sender.minimumValue)) + let percentage: Double = differenceFromRefferencepoint / Double(valueMargin / 2) + let sliderThumButtonWidth = 32.0 + let segment: Double = (Double(sender.bounds.width) - sliderThumButtonWidth) / 2 + return CGFloat(segment * percentage) + } +} diff --git a/caffeine/ViewController/StatisticsViewController.swift b/caffeine/ViewController/StatisticsViewController.swift new file mode 100644 index 0000000..472bd43 --- /dev/null +++ b/caffeine/ViewController/StatisticsViewController.swift @@ -0,0 +1,165 @@ +import Foundation +import UIKit +import Spring + +/* +* +* This ViewController will implement the UICaffeineStatisticsChartView (SwiftCharts Library) +* It will display the Caffeine Blod Concentration over a given period of time. +* Above that it could be possible to change the time eg. 12h, 24h, 48h. +* Maybe more statistical relevant content like how much milk, coffee, sugar was consumed +* during the last 30 days. +* +*/ +class StatisticsViewController: UIViewController { + + @IBOutlet private weak var timeSelectorView: UICaffeineStatisticsTimeSelectorView? + @IBOutlet private weak var statisticsChartView: UICaffeineStatisticsChartView? + @IBOutlet private weak var caffeineRateLabel: UILabel? + @IBOutlet private weak var totalCupsLabel: UILabel? + @IBOutlet private weak var totalMilkLabel: UILabel? + @IBOutlet private weak var totalSugarLabel: UILabel? + + @IBOutlet private weak var totalShotsImageView: DesignableImageView? + @IBOutlet private weak var totalMilkImageView: DesignableImageView? + @IBOutlet private weak var totalSugarImageView: DesignableImageView? + + @IBOutlet private weak var leftStatisticsDescriptionLabel: UILabel? + @IBOutlet private weak var centerStatisticsDescriptionLabel: UILabel? + @IBOutlet private weak var rightStatisticsDescriptionLabel: UILabel? + + private var selectorState: SelectorState = .day + + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + + updateStatisticsChartView() + + CaffeineDataService.shared.getCaffeineConcentration { (success, caffeineReturn) -> Void in + guard success, let caffeineReturn = caffeineReturn else { return } + DispatchQueue.main.async( + execute: { [weak self] () -> Void in + self?.caffeineRateLabel?.text = "\(Int(round(caffeineReturn)))" + } + ) + } + updateTotalLabels() + animate() + } + + override func viewWillDisappear(_ animated: Bool) { + super.viewWillDisappear(animated) + for totalImageView in [totalShotsImageView, totalMilkImageView, totalSugarImageView] { + totalImageView?.isHidden = true + } + } + + @IBAction private func dayButtonTapped(_ sender: AnyObject) { + timeSelectorView?.buttonTapped(with: .day) + selectorState = .day + updateStatisticsChartView() + updateTotalLabels() + } + + @IBAction private func weekButtonTapped(_ sender: AnyObject) { + timeSelectorView?.buttonTapped(with: .week) + selectorState = .week + updateStatisticsChartView() + updateTotalLabels() + } + + @IBAction private func monthButtonTapped(_ sender: AnyObject) { + timeSelectorView?.buttonTapped(with: .month) + selectorState = .month + updateStatisticsChartView() + updateTotalLabels() + } + + @IBAction private func yearButtonTapped(_ sender: AnyObject) { + timeSelectorView?.buttonTapped(with: .year) + selectorState = .year + updateStatisticsChartView() + updateTotalLabels() + } + + private func updateStatisticsChartView() { + let consumption = DrinksService.shared.getConsumption(for: .init(with: selectorState)) + let distance = intersectDistance[selectorState.rawValue] + let catmull = catmullRomSelection[selectorState.rawValue] + + statisticsChartView?.setUpGraphView( + consumption.periodicData.map { + $0.reduce( + 0.0, { $0 + ConsumableProperties($1).caffeine } + ) + }, + intersectDistance: distance, + catmullRom: catmull + ) + + switch (selectorState) { + case .day: + leftStatisticsDescriptionLabel?.text = "0" + centerStatisticsDescriptionLabel?.text = "12" + rightStatisticsDescriptionLabel?.text = "24" + case .week: + guard Calendar.current.shortWeekdaySymbols.count >= 6 else { return } + leftStatisticsDescriptionLabel?.text = Calendar.current.shortWeekdaySymbols[0] + centerStatisticsDescriptionLabel?.text = Calendar.current.shortWeekdaySymbols[3] + rightStatisticsDescriptionLabel?.text = Calendar.current.shortWeekdaySymbols[6] + case .month: + leftStatisticsDescriptionLabel?.text = "1st" + centerStatisticsDescriptionLabel?.text = "15th" + rightStatisticsDescriptionLabel?.text = "30th" + case .year: + guard Calendar.current.shortMonthSymbols.count >= 12 else { return } + leftStatisticsDescriptionLabel?.text = Calendar.current.shortMonthSymbols[0] + centerStatisticsDescriptionLabel?.text = "" + rightStatisticsDescriptionLabel?.text = Calendar.current.shortMonthSymbols[11] + } + } + + private func updateTotalLabels() { + let consumption = DrinksService.shared.getConsumption(for: .init(with: selectorState)) + + var milktext = "" + if consumption.milk < 1000 { + milktext = "\(Int(round(consumption.milk))) ml" + } else if consumption.milk < 100000 { + milktext = "\(String(format: "%.1f", consumption.milk / 1000)) l" + } else { + milktext = "\(Int(round(consumption.milk / 1000))) l" + } + + var sugartext = "" + if consumption.sugar < 1000 { + sugartext = "\(String(format: "%.1f", Double(consumption.sugar))) g" + } else if consumption.sugar < 100000 { + sugartext = "\(String(format: "%.1f", Double(consumption.sugar) / Double(1000))) kg" + } else { + sugartext = "\(Int(round(Double(consumption.sugar) / Double(1000)))) kg" + } + + totalCupsLabel?.text = "\(consumption.shots)" + totalMilkLabel?.text = milktext + totalSugarLabel?.text = sugartext + } + + private func animate() { + var counter: Int = 0 + for totalImageView in [totalShotsImageView, totalMilkImageView, totalSugarImageView] { + totalImageView?.isHidden = false + totalImageView?.animation = "fadeIn" + totalImageView?.delay = 0.1 + 0.3 * CGFloat(counter) + totalImageView?.force = 1.0 + totalImageView?.duration = 0.5 + totalImageView?.damping = 0.9 + totalImageView?.velocity = 0.5 + totalImageView?.scaleX = 0.5 + totalImageView?.scaleY = 0.5 + totalImageView?.curve = "spring" + counter += 1 + totalImageView?.animate() + } + } +} diff --git a/caffeine/caffeine.entitlements b/caffeine/caffeine.entitlements new file mode 100644 index 0000000..2ab14a2 --- /dev/null +++ b/caffeine/caffeine.entitlements @@ -0,0 +1,10 @@ + + + + + com.apple.developer.healthkit + + com.apple.developer.healthkit.access + + + diff --git a/caffeine/de.lproj/LaunchScreen.strings b/caffeine/de.lproj/LaunchScreen.strings new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/caffeine/de.lproj/LaunchScreen.strings @@ -0,0 +1 @@ + diff --git a/caffeine/de.lproj/Main.strings b/caffeine/de.lproj/Main.strings new file mode 100644 index 0000000..bb4919a --- /dev/null +++ b/caffeine/de.lproj/Main.strings @@ -0,0 +1,198 @@ + +/* Class = "UILabel"; text = "Female"; ObjectID = "02z-dn-G2q"; */ +"02z-dn-G2q.text" = "Weiblich"; + +/* Class = "UITabBarItem"; title = "Statistics"; ObjectID = "0Hr-Kn-Iax"; */ +"0Hr-Kn-Iax.title" = "Statistik"; + +/* Class = "UILabel"; text = "Lactose Free"; ObjectID = "1Qr-hz-Sc2"; */ +"1Qr-hz-Sc2.text" = "Laktosefrei"; + +/* Class = "UILabel"; text = "0"; ObjectID = "1V0-Rb-Rgv"; */ +"1V0-Rb-Rgv.text" = "0"; + +/* Class = "UILabel"; text = "TOTAL MILK"; ObjectID = "4Uz-Th-NJ3"; */ +"4Uz-Th-NJ3.text" = "MILCH GESAMT"; + +/* Class = "UILabel"; text = "Large"; ObjectID = "4qq-Xu-anz"; */ +"4qq-Xu-anz.text" = "Groß"; + +/* Class = "UILabel"; text = "0 %"; ObjectID = "5KO-yR-QRU"; */ +"5KO-yR-QRU.text" = "0 %"; + +/* Class = "UILabel"; text = "0"; ObjectID = "5g3-Rc-ZtG"; */ +"5g3-Rc-ZtG.text" = "0"; + +/* Class = "UILabel"; text = "Maximum Daily Intake:"; ObjectID = "6j2-AH-mcV"; */ +"6j2-AH-mcV.text" = "Maximaler tägl. Konsum:"; + +/* Class = "UINavigationItem"; title = "Statistics"; ObjectID = "Bm1-18-M96"; */ +"Bm1-18-M96.title" = "Statistik"; + +/* Class = "UILabel"; text = "24"; ObjectID = "BpZ-sz-LPF"; */ +"BpZ-sz-LPF.text" = "24"; + +/* Class = "UILabel"; text = "12"; ObjectID = "CTF-ux-Uua"; */ +"CTF-ux-Uua.text" = "12"; + +/* Class = "UITabBarItem"; title = "Consumption"; ObjectID = "D9d-aW-n7R"; */ +"D9d-aW-n7R.title" = "Konsum"; + +/* Class = "UILabel"; text = "Oral contraceptives:"; ObjectID = "Dx8-1t-RST"; */ +"Dx8-1t-RST.text" = "Antibabypille:"; + +/* Class = "UILabel"; text = "Recent Drinks:"; ObjectID = "FAz-NA-YSi"; */ +"FAz-NA-YSi.text" = "Kürzlich verwendet:"; + +/* Class = "UIButton"; normalTitle = "MONTH"; ObjectID = "FG1-Lg-jBi"; */ +"FG1-Lg-jBi.normalTitle" = "MONAT"; + +/* Class = "UILabel"; text = "50 %"; ObjectID = "Fd0-Sd-XBj"; */ +"Fd0-Sd-XBj.text" = "50 %"; + +/* Class = "UILabel"; text = "175 cm"; ObjectID = "GJc-es-2gE"; */ +"GJc-es-2gE.text" = "175 cm"; + +/* Class = "UILabel"; text = "2 Sugar"; ObjectID = "GcC-ch-tCo"; */ +"GcC-ch-tCo.text" = "2 Zucker"; + +/* Class = "UILabel"; text = "1 Sugar"; ObjectID = "GmS-Zt-HH9"; */ +"GmS-Zt-HH9.text" = "1 Zucker"; + +/* Class = "UITabBarItem"; title = "Input"; ObjectID = "Ius-ki-M3j"; */ +"Ius-ki-M3j.title" = "Eingabe"; + +/* Class = "UILabel"; text = "2 Shots"; ObjectID = "Ivs-47-qai"; */ +"Ivs-47-qai.text" = "2 Shots"; + +/* Class = "UILabel"; text = "3 Shots"; ObjectID = "JD5-Aw-Qvg"; */ +"JD5-Aw-Qvg.text" = "3 Shots"; + +/* Class = "UINavigationItem"; title = "Consumption"; ObjectID = "Ke8-uG-4YK"; */ +"Ke8-uG-4YK.title" = "Konsum"; + +/* Class = "UILabel"; text = "2 Shots"; ObjectID = "LbY-ke-QK2"; */ +"LbY-ke-QK2.text" = "2 Shots"; + +/* Class = "UILabel"; text = "TOTAL SHOTS"; ObjectID = "MCa-sT-gcY"; */ +"MCa-sT-gcY.text" = "SHOTS GESAMT"; + +/* Class = "UILabel"; text = "3 Shots"; ObjectID = "NyK-35-O8h"; */ +"NyK-35-O8h.text" = "3 Shots"; + +/* Class = "UILabel"; text = "50 kg"; ObjectID = "QU3-r5-AKx"; */ +"QU3-r5-AKx.text" = "50 kg"; + +/* Class = "UILabel"; text = "0 g"; ObjectID = "RIb-ij-VTN"; */ +"RIb-ij-VTN.text" = "0 g"; + +/* Class = "UILabel"; text = "3 Sugar"; ObjectID = "Reb-it-qmT"; */ +"Reb-it-qmT.text" = "3 Zucker"; + +/* Class = "UILabel"; text = "225 cm"; ObjectID = "TP7-Tc-2IS"; */ +"TP7-Tc-2IS.text" = "225 cm"; + +/* Class = "UILabel"; text = "Whole Milk"; ObjectID = "Txe-ek-Gor"; */ +"Txe-ek-Gor.text" = "Vollmilch"; + +/* Class = "UILabel"; text = "1 Shots"; ObjectID = "VGD-nL-Z1t"; */ +"VGD-nL-Z1t.text" = "1 Shots"; + +/* Class = "UILabel"; text = "TOTAL SUGAR"; ObjectID = "WLF-qd-JGA"; */ +"WLF-qd-JGA.text" = "ZUCKER GESAMT"; + +/* Class = "UILabel"; text = "Lactose Free, 1 Sugar"; ObjectID = "XUD-PP-L0S"; */ +"XUD-PP-L0S.text" = "Laktosefrei, 1 Zucker"; + +/* Class = "UILabel"; text = "180"; ObjectID = "YpP-Ki-Eaf"; */ +"YpP-Ki-Eaf.text" = "180"; + +/* Class = "UILabel"; text = "Sex:"; ObjectID = "ZHc-Pf-x4v"; */ +"ZHc-Pf-x4v.text" = "Geschlecht:"; + +/* Class = "UILabel"; text = "Height in cm:"; ObjectID = "aLE-Se-yr3"; */ +"aLE-Se-yr3.text" = "Größe in cm:"; + +/* Class = "UIButton"; normalTitle = "SAVE!"; ObjectID = "afE-hj-sQr"; */ +"afE-hj-sQr.normalTitle" = "SPEICHERN!"; + +/* Class = "UINavigationItem"; title = "Settings"; ObjectID = "boU-aK-bph"; */ +"boU-aK-bph.title" = "Einstellungen"; + +/* Class = "UILabel"; text = "Soy Milk, No Sugar"; ObjectID = "c3J-4C-bX0"; */ +"c3J-4C-bX0.text" = "Sojamilch, Kein Zucker"; + +/* Class = "UILabel"; text = "125 cm"; ObjectID = "dCl-4i-5Td"; */ +"dCl-4i-5Td.text" = "125 cm"; + +/* Class = "UILabel"; text = "Small"; ObjectID = "ehv-eN-oMe"; */ +"ehv-eN-oMe.text" = "Klein"; + +/* Class = "UILabel"; text = "Medium"; ObjectID = "fU3-cs-iwf"; */ +"fU3-cs-iwf.text" = "Medium"; + +/* Class = "UIButton"; normalTitle = "WEEK"; ObjectID = "h1N-7C-oBq"; */ +"h1N-7C-oBq.normalTitle" = "WOCHE"; + +/* Class = "UILabel"; text = "1 Shot"; ObjectID = "hN5-1X-Wet"; */ +"hN5-1X-Wet.text" = "1 Shot"; + +/* Class = "UILabel"; text = "CAFFEINE DOSE"; ObjectID = "iMj-M0-avC"; */ +"iMj-M0-avC.text" = "KOFFEIN DOSIS"; + +/* Class = "UILabel"; text = "Current Intake:"; ObjectID = "jCz-nl-aWo"; */ +"jCz-nl-aWo.text" = "Derzeitige Aufnahme:"; + +/* Class = "UIButton"; normalTitle = "DAY"; ObjectID = "jW2-Oe-2dp"; */ +"jW2-Oe-2dp.normalTitle" = "TAG"; + +/* Class = "UILabel"; text = "Soy Milk"; ObjectID = "lte-jz-J9Z"; */ +"lte-jz-J9Z.text" = "Sojamilch"; + +/* Class = "UILabel"; text = "mg"; ObjectID = "n0r-B3-41e"; */ +"n0r-B3-41e.text" = "mg"; + +/* Class = "UILabel"; text = "Sensiblity in %:"; ObjectID = "nUI-28-uki"; */ +"nUI-28-uki.text" = "Empfindlichkeit in %:"; + +/* Class = "UILabel"; text = "150 kg"; ObjectID = "oQS-aY-u2a"; */ +"oQS-aY-u2a.text" = "150 kg"; + +/* Class = "UIButton"; normalTitle = "YEAR"; ObjectID = "otl-fT-7FH"; */ +"otl-fT-7FH.normalTitle" = "JAHR"; + +/* Class = "UILabel"; text = "Male"; ObjectID = "pPR-WE-KCF"; */ +"pPR-WE-KCF.text" = "Männlich"; + +/* Class = "UILabel"; text = "mg"; ObjectID = "pqg-LB-a9a"; */ +"pqg-LB-a9a.text" = "mg"; + +/* Class = "UINavigationItem"; title = "Input"; ObjectID = "qGN-JZ-WQ5"; */ +"qGN-JZ-WQ5.title" = "Eingabe"; + +/* Class = "UILabel"; text = "100 %"; ObjectID = "qqf-UZ-HGN"; */ +"qqf-UZ-HGN.text" = "100 %"; + +/* Class = "UILabel"; text = "mg"; ObjectID = "rUn-St-jDK"; */ +"rUn-St-jDK.text" = "mg"; + +/* Class = "UILabel"; text = "350"; ObjectID = "s5a-zk-qu1"; */ +"s5a-zk-qu1.text" = "350"; + +/* Class = "UILabel"; text = "100 kg"; ObjectID = "tct-4Z-LQM"; */ +"tct-4Z-LQM.text" = "100 kg"; + +/* Class = "UILabel"; text = "Weight in kg:"; ObjectID = "tdT-Zs-JmM"; */ +"tdT-Zs-JmM.text" = "Gewicht in kg:"; + +/* Class = "UILabel"; text = "Whole Milk, 2 Sugar"; ObjectID = "voV-HE-PCG"; */ +"voV-HE-PCG.text" = "Vollmilch, 2 Zucker"; + +/* Class = "UILabel"; text = "0 ml"; ObjectID = "w6f-EU-tV6"; */ +"w6f-EU-tV6.text" = "0 ml"; + +/* Class = "UITabBarItem"; title = "Settings"; ObjectID = "xN8-1N-Dxw"; */ +"xN8-1N-Dxw.title" = "Einstellungen"; + +/* Class = "UILabel"; text = "0"; ObjectID = "ybR-m9-Q76"; */ +"ybR-m9-Q76.text" = "0"; diff --git a/caffeineUITests/Info.plist b/caffeineUITests/Info.plist new file mode 100644 index 0000000..64d65ca --- /dev/null +++ b/caffeineUITests/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/caffeineUITests/caffeineUITests.swift b/caffeineUITests/caffeineUITests.swift new file mode 100644 index 0000000..740fbc5 --- /dev/null +++ b/caffeineUITests/caffeineUITests.swift @@ -0,0 +1,90 @@ +// +// caffeineUITests.swift +// caffeineUITests +// +// Created by cr0ss on 18.09.15. +// Copyright © 2015 kayos. All rights reserved. +// + +import XCTest + +class caffeineUITests: XCTestCase { + + private var app: XCUIApplication? + + override func setUp() { + super.setUp() + + continueAfterFailure = true + let app = XCUIApplication() + setupSnapshot(app) + self.app = app + self.app?.launch() + } + + func testScreenshots() { + + if app?.staticTexts.containing(.init(format: "label CONTAINS[c] %@", "Turn All Categories On")).count ?? 0 > 0 { + app?.tables.staticTexts["Turn All Categories On"].tap() + app?.navigationBars["Health Access"].buttons["Allow"].tap() + } else if app?.staticTexts.containing(.init(format: "label CONTAINS[c] %@", "All Categories On")).count ?? 0 > 0 { + app?.tables.staticTexts["All Categories On"].tap() + app?.navigationBars["Health Access"].buttons["Allow"].tap() + } + + snapshot("0-Consumption") + let tabBarsQuery = app?.tabBars + tabBarsQuery?.buttons.allElementsBoundByIndex[1].tap() + + let saveElementsQuery: XCUIElementQuery? + + saveElementsQuery = app?.scrollViews.otherElements.containing( + .button, + identifier: "input_save_button" + ) + + saveElementsQuery?.children(matching: .other) + .element(boundBy: 0) + .children(matching: .other) + .element(boundBy: 1) + .children(matching: .button) + .element + .tap() + saveElementsQuery? + .children(matching: .other) + .element(boundBy: 1) + .children(matching: .other) + .element(boundBy: 1) + .children(matching: .button) + .element + .tap() + saveElementsQuery? + .children(matching: .other) + .element(boundBy: 2) + .children(matching: .other) + .element(boundBy: 0) + .children(matching: .button) + .element + .tap() + saveElementsQuery? + .children(matching: .other) + .element(boundBy: 3) + .children(matching: .other) + .element(boundBy: 0) + .children(matching: .button) + .element + .tap() + + snapshot("1-Input") + app?.scrollViews.otherElements.buttons["input_save_button"].tap() + + tabBarsQuery?.buttons.allElementsBoundByIndex[2].tap() + snapshot("2-Daily") + + app?.scrollViews.otherElements.buttons.allElementsBoundByIndex[1].tap() + snapshot("3-Monthly") + + tabBarsQuery?.buttons.allElementsBoundByIndex[3].tap() + snapshot("4-Settings") + } +} diff --git a/fastlane/Fastfile b/fastlane/Fastfile new file mode 100644 index 0000000..0615b88 --- /dev/null +++ b/fastlane/Fastfile @@ -0,0 +1,18 @@ +# Customise this file, documentation can be found here: +# https://github.com/fastlane/fastlane/tree/master/fastlane/docs +# All available actions: https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Actions.md +# can also be listed using the `fastlane actions` command +# All lines starting with a # are ignored when running `fastlane` +default_platform :ios + +platform :ios do + desc "Creates new screenshots and uploads them to iTunes Connect" + lane :screens do + snapshot + frame + end + + lane :frame do + frameit(path: "./fastlane/screenshots") + end +end diff --git a/fastlane/README.md b/fastlane/README.md new file mode 100644 index 0000000..645286e --- /dev/null +++ b/fastlane/README.md @@ -0,0 +1,34 @@ +fastlane documentation +================ +# Installation + +Make sure you have the latest version of the Xcode command line tools installed: + +``` +xcode-select --install +``` + +Install _fastlane_ using +``` +[sudo] gem install fastlane -NV +``` +or alternatively using `brew cask install fastlane` + +# Available Actions +## iOS +### ios screens +``` +fastlane ios screens +``` +Creates new screenshots and uploads them to iTunes Connect +### ios frame +``` +fastlane ios frame +``` + + +---- + +This README.md is auto-generated and will be re-generated every time [fastlane](https://fastlane.tools) is run. +More information about fastlane can be found on [fastlane.tools](https://fastlane.tools). +The documentation of fastlane can be found on [docs.fastlane.tools](https://docs.fastlane.tools). diff --git a/fastlane/Snapfile b/fastlane/Snapfile new file mode 100644 index 0000000..12cc7cc --- /dev/null +++ b/fastlane/Snapfile @@ -0,0 +1,29 @@ +# Uncomment the lines below you want to change by removing the # in the beginning +# A list of devices you want to take the screenshots from +devices([ + "iPhone 8 Plus", + "iPhone 11 Pro Max", +]) + +languages([ + "en-US", + "de-DE", +]) + +# Arguments to pass to the app on launch. See https://github.com/fastlane/snapshot#launch-arguments +# launch_arguments(["-favColor red"]) + +# The name of the scheme which contains the UI Tests +scheme "caffeineUITests" + +# Where should the resulting screenshots be stored? +output_directory "./fastlane/screenshots" + +clear_previous_screenshots true # remove the '#' to clear all previously generated screenshots before creating new ones + +# Choose which project/workspace to use +# project "./Project.xcodeproj" +workspace "./caffeine.xcworkspace" + +# For more information about all available options run +# snapshot --help diff --git a/fastlane/SnapshotHelper.swift b/fastlane/SnapshotHelper.swift new file mode 100644 index 0000000..2f08cf2 --- /dev/null +++ b/fastlane/SnapshotHelper.swift @@ -0,0 +1,279 @@ +// +// SnapshotHelper.swift +// Example +// +// Created by Felix Krause on 10/8/15. +// +// ----------------------------------------------------- +// IMPORTANT: When modifying this file, make sure to +// increment the version number at the very +// bottom of the file to notify users about +// the new SnapshotHelper.swift +// ----------------------------------------------------- +import Foundation +import XCTest + +var deviceLanguage = "" +var locale = "" + +func setupSnapshot(_ app: XCUIApplication, waitForAnimations: Bool = true) { + Snapshot.setupSnapshot(app, waitForAnimations: waitForAnimations) +} + +func snapshot(_ name: String, waitForLoadingIndicator: Bool) { + if waitForLoadingIndicator { + Snapshot.snapshot(name) + } else { + Snapshot.snapshot(name, timeWaitingForIdle: 0) + } +} + +/// - Parameters: +/// - name: The name of the snapshot +/// - timeout: Amount of seconds to wait until the network loading indicator disappears. Pass `0` if you don't want to wait. +func snapshot(_ name: String, timeWaitingForIdle timeout: TimeInterval = 20) { + Snapshot.snapshot(name, timeWaitingForIdle: timeout) +} + +enum SnapshotError: Error, CustomDebugStringConvertible { + case cannotFindSimulatorHomeDirectory + case cannotRunOnPhysicalDevice + + var debugDescription: String { + switch self { + case .cannotFindSimulatorHomeDirectory: + return "Couldn't find simulator home location. Please, check SIMULATOR_HOST_HOME env variable." + case .cannotRunOnPhysicalDevice: + return "Can't use Snapshot on a physical device." + } + } +} + +@objcMembers +open class Snapshot: NSObject { + static var app: XCUIApplication? + static var waitForAnimations = true + static var cacheDirectory: URL? + static var screenshotsDirectory: URL? { + return cacheDirectory?.appendingPathComponent("screenshots", isDirectory: true) + } + + open class func setupSnapshot(_ app: XCUIApplication, waitForAnimations: Bool = true) { + + Snapshot.app = app + Snapshot.waitForAnimations = waitForAnimations + + do { + let cacheDir = try getCacheDirectory() + Snapshot.cacheDirectory = cacheDir + setLanguage(app) + setLocale(app) + setLaunchArguments(app) + } catch let error { + NSLog(error.localizedDescription) + } + } + + class func setLanguage(_ app: XCUIApplication) { + guard let cacheDirectory = self.cacheDirectory else { + NSLog("CacheDirectory is not set - probably running on a physical device?") + return + } + + let path = cacheDirectory.appendingPathComponent("language.txt") + + do { + let trimCharacterSet = CharacterSet.whitespacesAndNewlines + deviceLanguage = try String(contentsOf: path, encoding: .utf8).trimmingCharacters(in: trimCharacterSet) + app.launchArguments += ["-AppleLanguages", "(\(deviceLanguage))"] + } catch { + NSLog("Couldn't detect/set language...") + } + } + + class func setLocale(_ app: XCUIApplication) { + guard let cacheDirectory = self.cacheDirectory else { + NSLog("CacheDirectory is not set - probably running on a physical device?") + return + } + + let path = cacheDirectory.appendingPathComponent("locale.txt") + + do { + let trimCharacterSet = CharacterSet.whitespacesAndNewlines + locale = try String(contentsOf: path, encoding: .utf8).trimmingCharacters(in: trimCharacterSet) + } catch { + NSLog("Couldn't detect/set locale...") + } + + if locale.isEmpty && !deviceLanguage.isEmpty { + locale = Locale(identifier: deviceLanguage).identifier + } + + if !locale.isEmpty { + app.launchArguments += ["-AppleLocale", "\"\(locale)\""] + } + } + + class func setLaunchArguments(_ app: XCUIApplication) { + guard let cacheDirectory = self.cacheDirectory else { + NSLog("CacheDirectory is not set - probably running on a physical device?") + return + } + + let path = cacheDirectory.appendingPathComponent("snapshot-launch_arguments.txt") + app.launchArguments += ["-FASTLANE_SNAPSHOT", "YES", "-ui_testing"] + + do { + let launchArguments = try String(contentsOf: path, encoding: String.Encoding.utf8) + let regex = try NSRegularExpression(pattern: "(\\\".+?\\\"|\\S+)", options: []) + let matches = regex.matches(in: launchArguments, options: [], range: NSRange(location: 0, length: launchArguments.count)) + let results = matches.map { result -> String in + (launchArguments as NSString).substring(with: result.range) + } + app.launchArguments += results + } catch { + NSLog("Couldn't detect/set launch_arguments...") + } + } + + open class func snapshot(_ name: String, timeWaitingForIdle timeout: TimeInterval = 20) { + if timeout > 0 { + waitForLoadingIndicatorToDisappear(within: timeout) + } + + NSLog("snapshot: \(name)") // more information about this, check out https://docs.fastlane.tools/actions/snapshot/#how-does-it-work + if Snapshot.waitForAnimations { + sleep(1) // Waiting for the animation to be finished (kind of) + } + + #if os(OSX) + guard let app = self.app else { + NSLog("XCUIApplication is not set. Please call setupSnapshot(app) before snapshot().") + return + } + + app.typeKey(XCUIKeyboardKeySecondaryFn, modifierFlags: []) + #else + + guard self.app != nil else { + NSLog("XCUIApplication is not set. Please call setupSnapshot(app) before snapshot().") + return + } + + let screenshot = XCUIScreen.main.screenshot() + guard var simulator = ProcessInfo().environment["SIMULATOR_DEVICE_NAME"], let screenshotsDir = screenshotsDirectory else { return } + + do { + // The simulator name contains "Clone X of " inside the screenshot file when running parallelized UI Tests on concurrent devices + let regex = try NSRegularExpression(pattern: "Clone [0-9]+ of ") + let range = NSRange(location: 0, length: simulator.count) + simulator = regex.stringByReplacingMatches(in: simulator, range: range, withTemplate: "") + + let path = screenshotsDir.appendingPathComponent("\(simulator)-\(name).png") + try screenshot.pngRepresentation.write(to: path) + } catch let error { + NSLog("Problem writing screenshot: \(name) to \(screenshotsDir)/\(simulator)-\(name).png") + NSLog(error.localizedDescription) + } + #endif + } + + class func waitForLoadingIndicatorToDisappear(within timeout: TimeInterval) { + #if os(tvOS) + return + #endif + + guard let app = self.app else { + NSLog("XCUIApplication is not set. Please call setupSnapshot(app) before snapshot().") + return + } + + let networkLoadingIndicator = app.otherElements.deviceStatusBars.networkLoadingIndicators.element + let networkLoadingIndicatorDisappeared = XCTNSPredicateExpectation(predicate: NSPredicate(format: "exists == false"), object: networkLoadingIndicator) + _ = XCTWaiter.wait(for: [networkLoadingIndicatorDisappeared], timeout: timeout) + } + + class func getCacheDirectory() throws -> URL { + let cachePath = "Library/Caches/tools.fastlane" + // on OSX config is stored in /Users//Library + // and on iOS/tvOS/WatchOS it's in simulator's home dir + #if os(OSX) + let homeDir = URL(fileURLWithPath: NSHomeDirectory()) + return homeDir.appendingPathComponent(cachePath) + #elseif arch(i386) || arch(x86_64) + guard let simulatorHostHome = ProcessInfo().environment["SIMULATOR_HOST_HOME"] else { + throw SnapshotError.cannotFindSimulatorHomeDirectory + } + let homeDir = URL(fileURLWithPath: simulatorHostHome) + return homeDir.appendingPathComponent(cachePath) + #else + throw SnapshotError.cannotRunOnPhysicalDevice + #endif + } +} + +private extension XCUIElementAttributes { + var isNetworkLoadingIndicator: Bool { + if hasAllowListedIdentifier { return false } + + let hasOldLoadingIndicatorSize = frame.size == CGSize(width: 10, height: 20) + let hasNewLoadingIndicatorSize = frame.size.width.isBetween(46, and: 47) && frame.size.height.isBetween(2, and: 3) + + return hasOldLoadingIndicatorSize || hasNewLoadingIndicatorSize + } + + var hasAllowListedIdentifier: Bool { + let allowListedIdentifiers = ["GeofenceLocationTrackingOn", "StandardLocationTrackingOn"] + + return allowListedIdentifiers.contains(identifier) + } + + func isStatusBar(_ deviceWidth: CGFloat) -> Bool { + if elementType == .statusBar { return true } + guard frame.origin == .zero else { return false } + + let oldStatusBarSize = CGSize(width: deviceWidth, height: 20) + let newStatusBarSize = CGSize(width: deviceWidth, height: 44) + + return [oldStatusBarSize, newStatusBarSize].contains(frame.size) + } +} + +private extension XCUIElementQuery { + var networkLoadingIndicators: XCUIElementQuery { + let isNetworkLoadingIndicator = NSPredicate { (evaluatedObject, _) in + guard let element = evaluatedObject as? XCUIElementAttributes else { return false } + + return element.isNetworkLoadingIndicator + } + + return self.containing(isNetworkLoadingIndicator) + } + + var deviceStatusBars: XCUIElementQuery { + guard let app = Snapshot.app else { + fatalError("XCUIApplication is not set. Please call setupSnapshot(app) before snapshot().") + } + + let deviceWidth = app.windows.firstMatch.frame.width + + let isStatusBar = NSPredicate { (evaluatedObject, _) in + guard let element = evaluatedObject as? XCUIElementAttributes else { return false } + + return element.isStatusBar(deviceWidth) + } + + return self.containing(isStatusBar) + } +} + +private extension CGFloat { + func isBetween(_ numberA: CGFloat, and numberB: CGFloat) -> Bool { + return numberA...numberB ~= self + } +} + +// Please don't remove the lines below +// They are used to detect outdated configuration files +// SnapshotHelperVersion [1.23] diff --git a/fastlane/screenshots/Framefile.json b/fastlane/screenshots/Framefile.json new file mode 100644 index 0000000..1fcd4e3 --- /dev/null +++ b/fastlane/screenshots/Framefile.json @@ -0,0 +1,44 @@ +{ + "device_frame_version": "latest", + "default": { + "background": "./background.jpg", + "padding": 50, + "show_complete_frame": false, + "stack_title" : false, + "title_below_image": false, + "frame": "WHITE", + "use_platform": "IOS" + }, + "data": [ + { + "filter": "Consumption", + "title": { + "color": "#ffffff" + } + }, + { + "filter": "Input", + "title": { + "color": "#ffffff" + } + }, + { + "filter": "Daily", + "title": { + "color": "#ffffff" + } + }, + { + "filter": "Monthly", + "title": { + "color": "#ffffff" + } + }, + { + "filter": "Settings", + "title": { + "color": "#ffffff" + } + } + ] +} diff --git a/fastlane/screenshots/background.jpg b/fastlane/screenshots/background.jpg new file mode 100644 index 0000000000000000000000000000000000000000..68688642aadefcf4e8808e2e19a574d64589d9ad GIT binary patch literal 19826 zcmeI0NpKWp7>57eW(iWmghj=JoepTk%5*YG)R|(4kPrh^V@W_j4_3|6NyeC&VWx4K zRCxdwG&fw)Q$PjvhKlP!QCv@k9W1MiyIur$EvwqM+hKC?KzZf;X1eE_?*IS({+{l` zQ|+E|KNs`X4y+jvk|e|+KEj<5yH`7fVIk6Ku}laN5&?|{ntxn~ zjnWm3{0^yYcKptQQ0rq*(+{kITHbozuQG+r&v0x?K0jI&Q_5_P^SH8b%cyOalcrg$ z#xnU*){5myI&(%^PwPW4T1$=v|>NcaqL{dEBxyx-))Pv6^&JhF?61+&gR#%W>@mV$)Wy%`ds`=8TE^-)oQU?SFBVSF*_59gxL`{Q7+8L+4 zSZzIDq2H?JDuuFLC>3?DVkTSKYNrgt#0qA82`_D2>k6Gg0wh2JBtQZraPbkCwH>Pn z#i_w%g!{ILhE!;iA{j!CN=j664~r|IS(@aB=TTlrvZ88%U?|))2Lley6SAZzvZ`pB z3R{!z!Fi!ZwdR)2m4W%|GC^a@g824bdqS zsH(Me2AWr{3ud;=H{#nv3s&vgbKp?8wQK0?!fa)_Y0;AInWg8v*8I*ctg#*ctFuO9 zvweLk`h@INMqHx6{G&=#^oqZ$dnd1*k|*0P+AZRKLI@Fenh+xH5kiQ#M+qU~9wUT^dz=s= z?g>JOxF-pLo&ZUtC-@NP33w9d34lOP00ephAkY&4ft~;ee4hXae4hXa^aMblCjbIH z0TAd3fIv?G1bPA>&=UZGo&X5+1VErC00KP$5a&=UZGo&X5+1VErC00KP$5a + + + fastlane/snapshot + + + + +
+ + +
+

By Language:

+

de-DE

+
+ + + + + + + + + + + + + + + + + + + + + +
+ iPhone 11 Pro Max +
+ + de-DE iPhone 11 Pro Max + + + + de-DE iPhone 11 Pro Max + + + + de-DE iPhone 11 Pro Max + + + + de-DE iPhone 11 Pro Max + + + + de-DE iPhone 11 Pro Max + +
+ iPhone 8 Plus +
+ + de-DE iPhone 8 Plus + + + + de-DE iPhone 8 Plus + + + + de-DE iPhone 8 Plus + + + + de-DE iPhone 8 Plus + + + + de-DE iPhone 8 Plus + +
+

en-US

+
+ + + + + + + + + + + + + + + + + + + + + +
+ iPhone 11 Pro Max +
+ + en-US iPhone 11 Pro Max + + + + en-US iPhone 11 Pro Max + + + + en-US iPhone 11 Pro Max + + + + en-US iPhone 11 Pro Max + + + + en-US iPhone 11 Pro Max + +
+ iPhone 8 Plus +
+ + en-US iPhone 8 Plus + + + + en-US iPhone 8 Plus + + + + en-US iPhone 8 Plus + + + + en-US iPhone 8 Plus + + + + en-US iPhone 8 Plus + +
+
+

By Screen:

+

0-Consumption

+
+ + + + + + + + + + + + + + + +
+ iPhone 11 Pro Max +
+ + de-DE iPhone 11 Pro Max + +
de-DE
+
+ + en-US iPhone 11 Pro Max + +
en-US
+
+ iPhone 8 Plus +
+ + de-DE iPhone 8 Plus + +
de-DE
+
+ + en-US iPhone 8 Plus + +
en-US
+
+

1-Input

+
+ + + + + + + + + + + + + + + +
+ iPhone 11 Pro Max +
+ + de-DE iPhone 11 Pro Max + +
de-DE
+
+ + en-US iPhone 11 Pro Max + +
en-US
+
+ iPhone 8 Plus +
+ + de-DE iPhone 8 Plus + +
de-DE
+
+ + en-US iPhone 8 Plus + +
en-US
+
+

2-Daily

+
+ + + + + + + + + + + + + + + +
+ iPhone 11 Pro Max +
+ + de-DE iPhone 11 Pro Max + +
de-DE
+
+ + en-US iPhone 11 Pro Max + +
en-US
+
+ iPhone 8 Plus +
+ + de-DE iPhone 8 Plus + +
de-DE
+
+ + en-US iPhone 8 Plus + +
en-US
+
+

3-Monthly

+
+ + + + + + + + + + + + + + + +
+ iPhone 11 Pro Max +
+ + de-DE iPhone 11 Pro Max + +
de-DE
+
+ + en-US iPhone 11 Pro Max + +
en-US
+
+ iPhone 8 Plus +
+ + de-DE iPhone 8 Plus + +
de-DE
+
+ + en-US iPhone 8 Plus + +
en-US
+
+

4-Settings

+
+ + + + + + + + + + + + + + + +
+ iPhone 11 Pro Max +
+ + de-DE iPhone 11 Pro Max + +
de-DE
+
+ + en-US iPhone 11 Pro Max + +
en-US
+
+ iPhone 8 Plus +
+ + de-DE iPhone 8 Plus + +
de-DE
+
+ + en-US iPhone 8 Plus + +
en-US
+
+
+
+ +
+
+ + + diff --git a/swiftlint.yml b/swiftlint.yml new file mode 100644 index 0000000..a7e0c8f --- /dev/null +++ b/swiftlint.yml @@ -0,0 +1,68 @@ +# entries after this are temporarily added. Remove one by one and fix! +# testing jenkins +disabled_rules: + +opt_in_rules: + - nesting + - redundant_optional_initialization + - closure_end_indentation + - contains_over_first_not_nil + - empty_parameters + - force_unwrapping + +# autocorrect: + - explicit_init + - closure_spacing + - operator_usage_whitespace + +# manually: + - empty_count + - private_outlet + - private_action + - private_over_fileprivate + - implicitly_unwrapped_optional + - let_var_whitespace + - yoda_condition + - first_where + - for_where + - multiline_arguments + - multiline_arguments_brackets + - multiline_function_chains + - multiline_literal_brackets + - multiple_closures_with_trailing_closure + - no_space_in_method_call + +excluded: + - Pods + - Templates + - GMRChat + - Frameworks + - GMRUnitTests + +# make it difficult to forget +force_unwrapping: warning +force_cast: error +implicitly_unwrapped_optional: error +multiline_arguments: error +multiline_arguments_brackets: error +multiline_function_chains: error +multiline_literal_brackets: error +multiple_closures_with_trailing_closure: error +no_space_in_method_call: error +private_outlet: error +private_action: error +private_over_fileprivate: error + +cyclomatic_complexity: + - 20 # warning + - 30 # error +type_body_length: + - 450 # warning + - 600 # error +function_body_length: + - 100 # warning + - 200 # error +file_length: + - 600 # warning + - 1000 # error +